summaryrefslogtreecommitdiff
path: root/src/application/mystic/forum
diff options
context:
space:
mode:
Diffstat (limited to 'src/application/mystic/forum')
-rw-r--r--src/application/mystic/forum/Database.php26
-rw-r--r--src/application/mystic/forum/Messaging.php101
-rw-r--r--src/application/mystic/forum/attributes/References.php5
-rw-r--r--src/application/mystic/forum/exceptions/DatabaseConnectionException.php6
-rw-r--r--src/application/mystic/forum/orm/Post.php2
-rw-r--r--src/application/mystic/forum/utils/RequestUtils.php19
6 files changed, 156 insertions, 3 deletions
diff --git a/src/application/mystic/forum/Database.php b/src/application/mystic/forum/Database.php
index f574386..9b9cf55 100644
--- a/src/application/mystic/forum/Database.php
+++ b/src/application/mystic/forum/Database.php
@@ -10,6 +10,7 @@ use mystic\forum\attributes\NotNull;
use mystic\forum\attributes\PrimaryKey;
use mystic\forum\attributes\References;
use mystic\forum\attributes\Table;
+use mystic\forum\exceptions\DatabaseConnectionException;
use mystic\forum\orm\Entity;
use mystic\forum\utils\ArrayUtils;
use mystic\forum\utils\StringUtils;
@@ -26,7 +27,13 @@ class Database {
private const REFERENCES = 0b0000_0100;
public function __construct(string $connectionString) {
- $this->connection = \pg_connect($connectionString);
+ try {
+ $conn = \pg_connect($connectionString);
+ if ($conn !== false)
+ $this->connection = $conn;
+ } catch (\ErrorException $ex) {
+ throw new DatabaseConnectionException($ex->getMessage(), $ex->getCode(), $ex);
+ }
}
public static function getConnectionString(string $host, string $user, string $password, string $dbname, int $port = 5432): string {
@@ -281,6 +288,23 @@ class Database {
return true;
}
+ public function delete(Entity &$entity): bool {
+ $entityClassName = get_class($entity);
+ $tableName = self::getTableName($entityClassName);
+ $reflClass = new ReflectionClass($entityClassName);
+ $cols = self::getColumns($reflClass);
+ $primaryCol = self::getPrimaryKeyColumn($cols);
+ if ($primaryCol === null)
+ throw new \RuntimeException("Deleting an entity requires a primary key column to be specified");
+ $query = "DELETE FROM $tableName WHERE $primaryCol = \$1;";
+ $result = \pg_query_params($this->connection, $query, [ $entity->{$cols[$primaryCol]["propertyName"]} ]);
+ if ($result === false)
+ throw new \RuntimeException("Deletion failed: " . \pg_last_error($this->connection));
+ $num_affected_rows = \pg_affected_rows($result);
+ \pg_free_result($result);
+ return $num_affected_rows >= 1;
+ }
+
public function update(Entity &$entity): bool {
$tableName = self::getTableName(get_class($entity));
$reflClass = new ReflectionClass($entity);
diff --git a/src/application/mystic/forum/Messaging.php b/src/application/mystic/forum/Messaging.php
new file mode 100644
index 0000000..2f5c80d
--- /dev/null
+++ b/src/application/mystic/forum/Messaging.php
@@ -0,0 +1,101 @@
+<?php
+declare(strict_types=1);
+
+namespace mystic\forum;
+
+use mystic\forum\utils\StaticClass;
+
+final class Messaging {
+ use StaticClass;
+
+ const ENT_FLAGS = \ENT_COMPAT | \ENT_HTML401 | \ENT_SUBSTITUTE;
+
+ protected static function message(array $items, string $headerText, string $headerColor, string $headerTextColor): void {
+ echo "<HTML><BODY>\n";
+ echo "<TABLE cellspacing=2 cellpadding=0 bgcolor=gray><TR><TD>\n";
+
+ echo "<TABLE width=\"100%\" cellspacing=0 cellpadding=4 bgcolor=\"".htmlentities($headerColor, self::ENT_FLAGS)."\"><TR><TD align=center>\n";
+ echo "<FONT face=Arial size=3 color=\"".htmlentities($headerTextColor, self::ENT_FLAGS)."\"><B>".htmlentities($headerText, self::ENT_FLAGS)."</B></FONT>\n";
+ echo "</TD></TR></TABLE>\n";
+
+ echo "</TD></TR><TR><TD>\n";
+
+ echo "<TABLE cellspacing=0 cellpadding=4 bgcolor=WHITE><TR><TD align=left><FONT size=2 face=Arial color=BLACK>\n";
+
+ foreach ($items as $item) {
+ if (is_scalar($item)) {
+ echo "<P>" . htmlentities(strval($item), self::ENT_FLAGS) . "</P>\n";
+ } elseif (is_array($item)) {
+ if (count(array_keys($item)) === 2 && isset($item["___!type"]) && isset($item["___!content"])) {
+ // special item
+ switch ($item["___!type"]) {
+ case "HTML":
+ echo $item["___!content"];
+ break;
+ default:
+ echo "invalid";
+ break;
+ }
+ } elseif (array_is_list($item)) {
+ echo "<UL>\n";
+ foreach ($item as $i)
+ echo "<LI>" . htmlentities($i, self::ENT_FLAGS) . "</LI>\n";
+ echo "</UL>\n";
+ } else {
+ echo "<TABLE cellspacing=0 cellpadding=2 border=1>\n";
+ foreach ($item as $k => $i) {
+ echo "<TR>\n";
+ echo "<TH align=left>" . htmlentities($k, self::ENT_FLAGS) . "</TH>\n";
+ echo "<TD>";
+ if (is_scalar($i)) {
+ echo htmlentities($i, self::ENT_FLAGS);
+ } else {
+ echo gettype($i);
+ }
+ echo "</TD>";
+ echo "</TR>\n";
+ }
+ echo "</TABLE>\n";
+ }
+ } else {
+ echo gettype($item);
+ }
+ }
+
+ echo "</FONT></TD></TR></TABLE>\n";
+
+ echo "</TD></TR></TABLE>\n";
+ echo "</BODY></HTML>\n";
+ }
+
+ public static function bold(string $contents): array {
+ return self::html("<P><B>" . htmlentities($contents, self::ENT_FLAGS) . "</B></P>\n");
+ }
+
+ public static function italic(string $contents): array {
+ return self::html("<P><I>" . htmlentities($contents, self::ENT_FLAGS) . "</I></P>\n");
+ }
+
+ public static function bold_italic(string $contents): array {
+ return self::html("<P><B><I>" . htmlentities($contents, self::ENT_FLAGS) . "</I></B></P>\n");
+ }
+
+ public static function html(string $contents): array {
+ return [
+ "___!type" => "HTML",
+ "___!content" => $contents,
+ ];
+ }
+
+ public static function info(string|array $contents): void {
+ if (is_string($contents))
+ $contents = [$contents];
+ self::message($contents, "INFORMATION", "SKYBLUE", "BLACK");
+ }
+
+ public static function error(string|array $contents): void {
+ if (is_string($contents))
+ $contents = [$contents];
+ self::message($contents, "ERROR", "RED", "WHITE");
+ }
+}
diff --git a/src/application/mystic/forum/attributes/References.php b/src/application/mystic/forum/attributes/References.php
index ac431ff..9e33927 100644
--- a/src/application/mystic/forum/attributes/References.php
+++ b/src/application/mystic/forum/attributes/References.php
@@ -7,9 +7,12 @@ class References {
public function __construct(
public readonly string $foreignTableName,
public readonly ?string $foreignColumnName = null,
+ public readonly bool $cascadeOnDelete = false,
) {}
public function __toString(): string {
- return $this->foreignTableName . ($this->foreignColumnName !== null ? " ({$this->foreignColumnName})" : "");
+ return $this->foreignTableName
+ . ($this->foreignColumnName !== null ? " ({$this->foreignColumnName})" : "")
+ . ($this->cascadeOnDelete ? " ON DELETE CASCADE" : "");
}
}
diff --git a/src/application/mystic/forum/exceptions/DatabaseConnectionException.php b/src/application/mystic/forum/exceptions/DatabaseConnectionException.php
new file mode 100644
index 0000000..f79d800
--- /dev/null
+++ b/src/application/mystic/forum/exceptions/DatabaseConnectionException.php
@@ -0,0 +1,6 @@
+<?php
+declare(strict_types=1);
+
+namespace mystic\forum\exceptions;
+
+class DatabaseConnectionException extends \Exception {}
diff --git a/src/application/mystic/forum/orm/Post.php b/src/application/mystic/forum/orm/Post.php
index db297e5..2c9a38c 100644
--- a/src/application/mystic/forum/orm/Post.php
+++ b/src/application/mystic/forum/orm/Post.php
@@ -13,5 +13,5 @@ class Post extends Entity {
public string $content;
#[References("public.users")] public string $authorId;
public \DateTimeImmutable $postDate;
- #[References("public.topics")] public string $topicId;
+ #[References("public.topics", cascadeOnDelete: true)] public string $topicId;
}
diff --git a/src/application/mystic/forum/utils/RequestUtils.php b/src/application/mystic/forum/utils/RequestUtils.php
new file mode 100644
index 0000000..2f40013
--- /dev/null
+++ b/src/application/mystic/forum/utils/RequestUtils.php
@@ -0,0 +1,19 @@
+<?php
+declare(strict_types=1);
+
+namespace mystic\forum\utils;
+
+use mystic\forum\Messaging;
+
+final class RequestUtils {
+ use StaticClass;
+
+ public static function ensureRequestMethod(string $method): void {
+ $rMethod = $_SERVER["REQUEST_METHOD"];
+ if (strcasecmp($rMethod, $method) !== 0) {
+ http_response_code(500);
+ Messaging::error("Invalid request method $rMethod");
+ exit;
+ }
+ }
+}