Forum implementiert #34

Merged
niklas.ortmann merged 20 commits from Forum into dev 2026-06-17 10:24:25 +02:00
6 changed files with 401 additions and 14 deletions
Showing only changes of commit eb56b8d6a0 - Show all commits
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="dataSourceStorageLocal" created-in="IU-261.24374.151">
<component name="dataSourceStorageLocal" created-in="IU-253.32098.101">
<data-source name="articles" uuid="315cb5c9-2b0f-435b-b602-59823b160908">
<database-info product="SQLite" version="3.51.1" jdbc-version="4.2" driver-name="SQLite JDBC" driver-version="3.51.1.0" dbms="SQLITE" exact-version="3.51.1" exact-driver-version="3.51">
<identifier-quote-string>&quot;</identifier-quote-string>
+70 -13
View File
@@ -1,18 +1,31 @@
<?php
include_once 'php/controller/showArticle-controller.php';
require_once 'php/model/CommentManager.php';
$comments = [];
if (isset($_GET["id"])) {
try {
$commentManager = CommentManager::getInstance();
$comments = $commentManager->getCommentsByArticle($_GET["id"]);
} catch (Exception $e) {
$_SESSION["message"] = "internal_error";
}
}
?>
<!--
Seite: Anzeige für Beiträge
Funktion: Stellt einen übergebenen Beitrag dar.
-->
<!-- Hauptcontainer für die Beitragsansicht (Ausschließlich der Content-Bereich) -->
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

Warum wurde der Kommentar entfernt?

Warum wurde der Kommentar entfernt?
<main class="article-view-container">
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "internal_error"): ?>
<p class="alert-message is-error">
Es ist ein interner Fehler aufgetreten. Bitte versuche es erneut.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "missing_id"): ?>
<p class="alert-message is-error">
Es ist ein Fehler aufgetreten. Die ID konnte nicht ausgelesen werden. Bitte versuche es erneut.
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

Warum werden die Error-Nachrichten gelöscht?!

Warum werden die Error-Nachrichten gelöscht?!
@@ -24,54 +37,59 @@ include_once 'php/controller/showArticle-controller.php';
Jeder Beitrag muss einen Titel, Kategorie und Inhalt besitzen.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "article_updated"): ?>
<p class="alert-message is-success">
Dein Beitrag wurde erfolgreich bearbeitet!
</p>
<?php endif; ?>
<?php
unset($_SESSION["message"]);
?>
<!-- Metadaten & Titel -->
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

Warum?

Warum?
<?php unset($_SESSION["message"]); ?>
<div class="article-view-top-section">
<?php if (isset($category) && !empty($category)): ?>
<span class="article-view-category"><?php echo htmlspecialchars($category); ?></span>
<?php endif; ?>
<h1 class="article-view-title">
<?php if (isset($title)) { echo htmlspecialchars($title); } ?>
</h1>
<div class="article-view-meta">
<?php if (isset($author) && !empty($author)): ?>
<span class="article-view-author">Von: <strong><?php echo htmlspecialchars($author); ?></strong></span>
<span class="article-view-author">
Von: <strong><?php echo htmlspecialchars($author); ?></strong>
</span>
<?php endif; ?>
</div>
</div>
<!-- Beitrags-Inhalt -->
<div class="article-view-content">
<?php if (isset($content)): ?>
<!-- nl2br für Zeilenumbrüche -->
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

?

?
<div class="article-view-body"><?php echo nl2br(htmlspecialchars($content)); ?></div>
<div class="article-view-body">
<?php echo nl2br(htmlspecialchars($content)); ?>
</div>
<?php endif; ?>
</div>
<!-- Beitrags-Endbereich (Tags) -->
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

?

?
<?php if (isset($tags) && !empty($tags)): ?>
<div class="article-view-bottom-section">
<div class="article-view-tags-label">Tags:</div>
<div class="article-view-tags-list">
<?php
// Falls $tags ein String ist (z.B. "Web, CSS"), in ein Array umwandeln
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

?

?
$tagArray = is_array($tags) ? $tags : explode(',', $tags);
foreach ($tagArray as $tag):
$trimmedTag = trim($tag);
if (!empty($trimmedTag)):
?>
<span class="article-view-tag-item"><?php echo htmlspecialchars($trimmedTag); ?></span>
<span class="article-view-tag-item">
<?php echo htmlspecialchars($trimmedTag); ?>
</span>
<?php
endif;
endforeach;
@@ -80,5 +98,44 @@ include_once 'php/controller/showArticle-controller.php';
</div>
<?php endif; ?>
</main>
<section class="article-comments-section">
<h2>Kommentare</h2>
<div id="comments-list">
<?php if (!empty($comments)): ?>
<?php foreach ($comments as $comment): ?>
<div class="comment-item">
<p>
<strong><?php echo htmlspecialchars($comment->getAuthor()); ?></strong>
<span><?php echo htmlspecialchars($comment->getCreated()); ?></span>
</p>
<p><?php echo nl2br(htmlspecialchars($comment->getContent())); ?></p>
</div>
<?php endforeach; ?>
<?php else: ?>
<p>Noch keine Kommentare vorhanden.</p>
<?php endif; ?>
</div>
<?php if (isset($_SESSION["user_email"])): ?>
<form id="comment-form">
<input type="hidden"
name="article_id"
value="<?php echo htmlspecialchars($_GET["id"] ?? ""); ?>">
<textarea name="content"
id="comment-content"
placeholder="Schreibe einen Kommentar..."
required></textarea>
<button type="submit" class="button">
Kommentar senden
</button>
</form>
<?php else: ?>
<p>Du musst angemeldet sein, um einen Kommentar zu schreiben.</p>
<?php endif; ?>
</section>
</main>
+92
View File
@@ -0,0 +1,92 @@
<?php
/**
* Repräsentiert einen Kommentar unter einem Beitrag.
*
* Ein Kommentar besteht aus einer eindeutigen ID,
* der ID des zugehörigen Beitrags, dem Autor,
* dem Inhalt sowie dem Erstellungsdatum.
*
* @author Caroline Schulte
*/
class Comment
{
private int $id;
private int $articleId;
private string $author;
private string $content;
private string $created;
/**
* Erstellt einen neuen Kommentar.
*
* @param int $id Eindeutige ID des Kommentars
* @param int $articleId ID des zugehörigen Beitrags
* @param string $author Autor des Kommentars
* @param string $content Inhalt des Kommentars
* @param string $created Erstellungsdatum des Kommentars
*/
public function __construct(
int $id,
int $articleId,
string $author,
string $content,
string $created
) {
$this->id = $id;
$this->articleId = $articleId;
$this->author = $author;
$this->content = $content;
$this->created = $created;
}
/**
* Gibt die ID des Kommentars zurück.
*
* @return int Kommentar-ID
*/
public function getId(): int
{
return $this->id;
}
/**
* Gibt die ID des zugehörigen Beitrags zurück.
*
* @return int Beitrags-ID
*/
public function getArticleId(): int
{
return $this->articleId;
}
/**
* Gibt den Autor des Kommentars zurück.
*
* @return string Autor
*/
public function getAuthor(): string
{
return $this->author;
}
/**
* Gibt den Inhalt des Kommentars zurück.
*
* @return string Kommentarinhalt
*/
public function getContent(): string
{
return $this->content;
}
/**
* Gibt das Erstellungsdatum des Kommentars zurück.
*
* @return string Erstellungsdatum
*/
public function getCreated(): string
{
return $this->created;
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
require_once "DatabaseCommentManager.php";
/**
* Zentrale Zugriffsschicht für Kommentare.
*
* Die Anwendung arbeitet ausschließlich
* mit dem CommentManager und kennt die
* konkrete Speicherimplementierung nicht.
*
* @author Caroline Schulte
*/
class CommentManager
{
/**
* Gibt die aktive Kommentarverwaltung zurück.
*
* @return CommentManagerDAO
*/
public static function getInstance()
{
return DatabaseCommentManager::getInstance();
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
require_once "Comment.php";
/**
* Schnittstelle für die Verwaltung von Kommentaren.
*
* Definiert die grundlegenden Methoden zum
* Speichern und Laden von Kommentaren.
*
* @author Caroline Schulte
*/
interface CommentManagerDAO
{
/**
* Speichert einen neuen Kommentar zu einem Beitrag.
*
* @param int $articleId ID des Beitrags
* @param string $author Autor des Kommentars
* @param string $content Inhalt des Kommentars
*
* @return void
*/
public function addComment(
$articleId,
$author,
$content
);
/**
* Gibt alle Kommentare eines Beitrags zurück.
*
* @param int $articleId ID des Beitrags
*
* @return Comment[] Liste der Kommentare
*/
public function getCommentsByArticle(
$articleId
);
}
+173
View File
@@ -0,0 +1,173 @@
<?php
require_once "CommentManagerDAO.php";
require_once "Comment.php";
/**
* Verwaltet die Speicherung und das Laden von Kommentaren
* über eine SQLite-Datenbank.
*
* @author Caroline Schulte
*/
class DatabaseCommentManager implements CommentManagerDAO
{
private static $instance = null;
/**
* Erstellt die Kommentartabelle,
* falls diese noch nicht existiert.
*/
public function __construct()
{
try {
$db = $this->getConnection();
$db->exec("
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
article_id INTEGER NOT NULL,
author TEXT NOT NULL,
content TEXT NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
");
unset($db);
} catch (PDOException $e) {
throw new RuntimeException(
"Kommentardatenbank konnte nicht erstellt werden."
);
}
}
/**
* Baut die Verbindung zur SQLite-Datenbank auf.
*
* @return PDO Datenbankverbindung
*/
private function getConnection()
{
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

Die genaue Formulierung der Fehlernachrichten wird ja in den views übernommen. Hier könnte man Fehlerkürzel wie
RuntimeException("internal_error") verwenden. In der view wird aus der Exception dann gelesen, was in dieser Stand. Wenn dort dann internal_error stand, dann wird eine bestimmte Fehlernachricht angezeigt.

Die genaue Formulierung der Fehlernachrichten wird ja in den views übernommen. Hier könnte man Fehlerkürzel wie RuntimeException("internal_error") verwenden. In der view wird aus der Exception dann gelesen, was in dieser Stand. Wenn dort dann internal_error stand, dann wird eine bestimmte Fehlernachricht angezeigt.
try {
$dsn = 'sqlite:' . __DIR__ . '/../../db/comments.db';
$db = new PDO($dsn, null, null);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $db;
} catch (PDOException $e) {
throw new RuntimeException(
"Verbindung zur Kommentardatenbank fehlgeschlagen."
);
}
}
/**
* Gibt die Singleton-Instanz zurück.
*
* @return DatabaseCommentManager
*/
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

s. oben

s. oben
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new DatabaseCommentManager();
}
return self::$instance;
}
/**
* Speichert einen neuen Kommentar
* zu einem Beitrag.
*
* @param int $articleId ID des Beitrags
* @param string $author Autor des Kommentars
* @param string $content Inhalt des Kommentars
*
* @return void
*/
public function addComment(
$articleId,
$author,
$content
) {
try {
$db = $this->getConnection();
$sql = "
INSERT INTO comments (
article_id,
author,
content
)
VALUES (
:articleId,
:author,
:content
)
";
$command = $db->prepare($sql);
$command->execute([
":articleId" => $articleId,
":author" => $author,
":content" => $content
]);
} catch (PDOException $e) {
throw new RuntimeException(
"Kommentar konnte nicht gespeichert werden."
);
}
}
/**
* Lädt alle Kommentare eines Beitrags.
*
* @param int $articleId ID des Beitrags
*
* @return Comment[]
*/
public function getCommentsByArticle(
$articleId
) {
try {
$db = $this->getConnection();
caroline.slt marked this conversation as resolved Outdated
Outdated
Review

s. oben

s. oben
$sql = "
SELECT *
FROM comments
WHERE article_id = :articleId
ORDER BY created DESC
";
$command = $db->prepare($sql);
$command->execute([
":articleId" => $articleId
]);
$comments = [];
while ($row = $command->fetch(PDO::FETCH_ASSOC)) {
$comments[] = new Comment(
$row["id"],
$row["article_id"],
$row["author"],
$row["content"],
$row["created"]
);
}
return $comments;
} catch (PDOException $e) {
throw new RuntimeException(
"Kommentare konnten nicht geladen werden."
);
}
}
}