Compare commits

..

1 Commits

Author SHA1 Message Date
NOrtmann1 87e595b13d Update updateArticle.php 2026-06-17 22:21:28 +02:00
26 changed files with 88 additions and 1507 deletions
-2
View File
@@ -19,8 +19,6 @@
- Die Suchseite und Kategorieseite packen momentan alle passenden Beiträge untereinander. Später sollen zunächst 10
Ergebnisse auf einer Seite angezeigt werden.
- Wenn ein Bild aus einem Beitrag entfernt wird, dann wird noch nicht die Datei im Pfad /uploads gelöscht.
- id in showArticle-controller.php und updateArticle-controller.php wird nicht als gültige numerische ID geprüft.
- sort in search-results-controller.php wird nicht gegen erlaubte Werte validiert.
## Besonderheiten des Projektes
- Es wurde ein einfacher Beitrags-Editor erstellt. Mit diesem können Beiträge erstellt oder bearbeitet werden.
+27 -193
View File
@@ -51,211 +51,45 @@ if (!isset($_SESSION["user"])) {
<div class="sidebar-block">
<label for="category">Kategorie <span class="required">*</span></label>
<select id="category" name="category" required>
<option disabled <?php
if ((!isset($_SESSION['old_category']) || empty($_SESSION['old_category'])) && (!isset($category) || empty($category))) {
echo 'selected';
}
?>>Kategorie wählen...</option>
<option value="" disabled selected>Kategorie wählen...</option>
<optgroup label="Sprachen">
<option value="deutsch" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'deutsch') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'deutsch') { echo 'selected'; }
}
?>>Deutsch</option>
<option value="englisch" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'englisch') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'englisch') { echo 'selected'; }
}
?>>Englisch</option>
<option value="franzoesisch" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'franzoesisch') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'franzoesisch') { echo 'selected'; }
}
?>>Französisch</option>
<option value="latein" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'latein') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'latein') { echo 'selected'; }
}
?>>Latein</option>
<option value="literatur" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'literatur') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'literatur') { echo 'selected'; }
}
?>>Literatur</option>
<option value="deutsch">Deutsch</option>
<option value="englisch">Englisch</option>
<option value="franzoesisch">Französisch</option>
<option value="latein">Latein</option>
<option value="literatur">Literatur</option>
</optgroup>
<optgroup label="MINT">
<option value="mathe" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'mathe') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'mathe') { echo 'selected'; }
}
?>>Mathematik</option>
<option value="biologie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'biologie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'biologie') { echo 'selected'; }
}
?>>Biologie</option>
<option value="chemie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'chemie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'chemie') { echo 'selected'; }
}
?>>Chemie</option>
<option value="physik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'physik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'physik') { echo 'selected'; }
}
?>>Physik</option>
<option value="informatik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'informatik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'informatik') { echo 'selected'; }
}
?>>Informatik</option>
<option value="astronomie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'astronomie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'astronomie') { echo 'selected'; }
}
?>>Astronomie</option>
<option value="mathe">Mathematik</option>
<option value="biologie">Biologie</option>
<option value="chemie">Chemie</option>
<option value="physik">Physik</option>
<option value="informatik">Informatik</option>
<option value="astronomie">Astronomie</option>
</optgroup>
<optgroup label="Gesellschaft & Werte">
<option value="geschichte" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'geschichte') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'geschichte') { echo 'selected'; }
}
?>>Geschichte</option>
<option value="erdkunde" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'erdkunde') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'erdkunde') { echo 'selected'; }
}
?>>Erdkunde</option>
<option value="sozialkunde" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'sozialkunde') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'sozialkunde') { echo 'selected'; }
}
?>>Sozialkunde</option>
<option value="wirtschaft" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'wirtschaft') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'wirtschaft') { echo 'selected'; }
}
?>>Wirtschaftskunde</option>
<option value="religion" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'religion') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'religion') { echo 'selected'; }
}
?>>Religion</option>
<option value="ethik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'ethik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'ethik') { echo 'selected'; }
}
?>>Ethikunterricht</option>
<option value="philosophie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'philosophie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'philosophie') { echo 'selected'; }
}
?>>Philosophie</option>
<option value="psychologie" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'psychologie') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'psychologie') { echo 'selected'; }
}
?>>Psychologie</option>
<option value="kunst" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'kunst') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'kunst') { echo 'selected'; }
}
?>>Kunst</option>
<option value="musik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'musik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'musik') { echo 'selected'; }
}
?>>Musik</option>
<option value="theater" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'theater') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'theater') { echo 'selected'; }
}
?>>Theater</option>
<option value="geschichte">Geschichte</option>
<option value="erdkunde">Erdkunde</option>
<option value="sozialkunde">Sozialkunde</option>
<option value="wirtschaft">Wirtschaftskunde</option>
<option value="religion">Religion</option>
<option value="ethik">Ethikunterricht</option>
<option value="philosophie">Philosophie</option>
<option value="psychologie">Psychologie</option>
<option value="kunst">Kunst</option>
<option value="musik">Musik</option>
<option value="theater">Theater</option>
</optgroup>
<optgroup label="Technik & Praxis">
<option value="technik" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'technik') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'technik') { echo 'selected'; }
}
?>>Technik</option>
<option value="werken" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'werken') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'werken') { echo 'selected'; }
}
?>>Werken</option>
<option value="hauswirtschaft" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'hauswirtschaft') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'hauswirtschaft') { echo 'selected'; }
}
?>>Hauswirtschaft</option>
<option value="sport" <?php
if (isset($_SESSION['old_category']) && !empty($_SESSION['old_category'])) {
if ($_SESSION['old_category'] === 'sport') { echo 'selected'; }
} elseif (isset($category) && !empty($category)) {
if ($category === 'sport') { echo 'selected'; }
}
?>>Sport</option>
<option value="technik">Technik</option>
<option value="werken">Werken</option>
<option value="hauswirtschaft">Hauswirtschaft</option>
<option value="sport">Sport</option>
</optgroup>
<?php
if (isset($_SESSION['old_category'])) {
unset($_SESSION['old_category']);
}
?>
</select>
</div>
+21 -27
View File
@@ -19,34 +19,28 @@ include_once 'php/controller/home-controller.php';
sea takimata sanctus est Lorem ipsum dolor sit amet.
</p>
<!-- Flexbox für aktive Kategorien -->
<div class="flexbox">
<?php
if (!empty($categoriesWithArticles) && is_array($categoriesWithArticles)):
foreach ($categoriesWithArticles as $category):
?>
<div class="container">
<a href="index.php?pfad=showCategory&category=<?php echo htmlspecialchars($category['slug']); ?>" class="category-link">
<?php echo htmlspecialchars($category['name']); ?>
</a>
<!-- Flexbox -->
<div class="flexbox">
<div class="container">
<a href="index.php?pfad=showCategory&category=informatik" class="category-link">Informatik</a>
<div class="article-link">
<a href="index.php?pfad=showArticle&id=<?php echo $dummy3->getId()?>"><?php if(isset($dummy3)){echo $dummy3->getTitle();}else{echo "Fehler: Beitrag nicht gefunden!";} ?></a>
</div>
</div>
<!-- die 5 neuesten Beiträge der Kategorie -->
<div class="article-links-wrapper">
<?php foreach ($category['articles'] as $article): ?>
<div class="article-link">
<a href="index.php?pfad=showArticle&id=<?php echo htmlspecialchars($article->getId()); ?>">
<?php echo htmlspecialchars($article->getTitle()); ?>
</a>
</div>
<?php endforeach; ?>
</div>
</div>
<?php
endforeach;
else:
?>
<p>Aktuell sind keine Beiträge in den Kategorien vorhanden.</p>
<?php endif; ?>
<div class="container">
<a href="index.php?pfad=showCategory&category=mathe" class="category-link">Mathe</a>
<div class="article-link">
<a href="index.php?pfad=showArticle&id=<?php echo $dummy1->getId()?>"><?php if(isset($dummy1)){echo $dummy1->getTitle();}else{echo "Fehler: Beitrag nicht gefunden!";} ?></a>
</div>
</div>
<div class="container">
<a href="index.php?pfad=showCategory&category=physik" class="category-link">Physik</a>
<div class="article-link">
<a href="index.php?pfad=showArticle&id=<?php echo $dummy2->getId()?>"><?php if(isset($dummy2)){echo $dummy2->getTitle();}else{echo "Fehler: Beitrag nicht gefunden!";} ?></a>
</div>
</div>
</div>
</main>
+7 -50
View File
@@ -7,8 +7,8 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
<main class="form-page">
<div class="flexbox">
<div class="container">
<?php include_once "includes/alertMessages.php" ?>
<?php if (!empty($error)): ?>
<p class="alert-message is-error">
@@ -93,6 +93,8 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
<div class="container">
<?php include_once "includes/alertMessages.php"?>
<h2 class="section-title">Meine Beiträge</h2>
<div class="articles-list">
@@ -155,9 +157,7 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
</a>
<form action="php/controller/deleteArticle-controller.php" method="POST">
<input type="hidden"
name="id"
value="<?php echo htmlspecialchars($userArticle->getID()); ?>">
<input type="hidden" name="id" value="<?php echo htmlspecialchars($userArticle->getID()); ?>">
<button type="submit"
class="button"
@@ -165,6 +165,7 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
Löschen
</button>
</form>
</div>
<?php endforeach; ?>
@@ -179,54 +180,10 @@ $isEditMode = (isset($_GET["edit"]) && $_GET["edit"] === "1") || !empty($error);
</button>
<?php endif; ?>
<?php unset($_SESSION["message"]); ?>
</div>
</div>
<div class="container">
<div class="comments-section">
<h2 class="section-title">Meine Kommentare</h2>
<!-- Liste aller Kommentare des Nutzers -->
<div class="comments-list">
<?php if (isset($userComments) && count($userComments) > 0): ?>
<?php foreach ($userComments as $comment): ?>
<div class="article-item">
<!-- Erstellungsdatum des Kommentars -->
<div class="article-meta">
<span class="article-date">
<?php echo htmlspecialchars($comment->getCreated()); ?>
</span>
</div>
<!-- Inhalt des Kommentars -->
<p>
<?php echo nl2br(htmlspecialchars($comment->getContent())); ?>
</p>
<!-- Link zum Beitrag, unter dem der Kommentar geschrieben wurde -->
<a href="index.php?pfad=showArticle&id=<?php echo htmlspecialchars($comment->getArticleId()); ?>"
class="edit-link-button">
Zum Beitrag
</a>
</div>
<?php endforeach; ?>
<?php else: ?>
<p>Du hast noch keine Kommentare geschrieben.</p>
<?php endif; ?>
</div>
</div>
</div>
<?php unset($_SESSION["message"]); ?>
</div>
</main>
+20 -76
View File
@@ -2,39 +2,19 @@
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$all_results = $_SESSION["search_results"] ?? [];
$results = $_SESSION["search_results"] ?? [];
$query = $_SESSION["search_query"] ?? "";
$totalResultsCount = count($all_results);
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
if (!in_array($limit, [10, 20, 50, 100])) {
$limit = 10;
}
$results = array_slice($results, 0, $limit);
// Gesamtseitenzahl
$totalPages = max(1, ceil($totalResultsCount / $limit));
// Aktuelle Seite auslesen und validieren
$currentPage = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($currentPage < 1) {
$currentPage = 1;
} elseif ($currentPage > $totalPages) {
$currentPage = $totalPages;
}
// Startpunkt im Array berechnen (Offset)
$offset = ($currentPage - 1) * $limit;
// Nur die Ergebnisse für die aktuelle Seite ausschneiden
//$results = array_slice($all_results, $offset, $limit);
$results = $all_results;
$resultCount = count($results);
?>
<noscript>
Bitte JavaScript aktivieren!
</noscript>
<!--
Seite: Suchergebnisse
Inhalt: Zeigt die Ergebnisse einer Suche an
@@ -45,10 +25,9 @@ $resultCount = count($results);
<!-- Links: Seitenleiste für Filter und Suche -->
<aside class="s-res-sidebar">
<form action="php/controller/search-results-controller.php" method="GET" id="search-form-id" class="s-res-sidebar-form">
<input type="hidden" id="s-res-page-input" name="page" value="<?php echo $_GET['page'] ?? 1; ?>">
<!-- Sortierfuntion Box und Such Box-->
<form id="search-form-id" action="php/controller/search-results-controller.php" method="GET" class="s-res-sidebar-form">
<div class="s-res-sidebar-box">
<h3 class="s-res-sidebar-title">Suche anpassen</h3>
<input type="search" id="site-search" name="q" placeholder="Suchen..." class="nav__search" value="<?php echo htmlspecialchars($query); ?>" maxlength="50" required>
@@ -60,57 +39,25 @@ $resultCount = count($results);
<?php $currentSort = $_SESSION['search_sort'] ?? 'alphabet'; ?>
<div class="s-res-filter-group">
<label class="s-res-filter-option">
<input type="radio" name="sort" value="alphabet" class="sort-radio" <?php echo $currentSort === 'alphabet' ? 'checked' : ''; ?>>
<input type="radio" name="sort" value="alphabet" <?php echo $currentSort === 'alphabet' ? 'checked' : ''; ?> onchange="this.form.submit()">
<span>Alphabetisch</span>
</label>
<!-- Noch disabled, da likes noch nicht implementiert-->
<label class="s-res-filter-option">
<input type="radio" name="sort" value="likes" class="sort-radio" <?php echo $currentSort === 'likes' ? 'checked' : ''; ?>>
<span>Beliebtheit</span>
<input type="radio" name="sort" value="likes" <?php echo $currentSort === 'likes' ? 'checked' : ''; ?> disabled>
<span style="color: #94a3b8;">Beliebtheit (Likes)</span>
</label>
<label class="s-res-filter-option">
<input type="radio" name="sort" value="newest" class="sort-radio" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?>>
<input type="radio" name="sort" value="newest" <?php echo $currentSort === 'newest' ? 'checked' : ''; ?> onchange="this.form.submit()">
<span>Neueste Beiträge</span>
</label>
<label class="s-res-filter-option">
<input type="radio" name="sort" value="oldest" class="sort-radio" <?php echo $currentSort === 'oldest' ? 'checked' : ''; ?>>
<input type="radio" name="sort" value="oldest" <?php echo $currentSort === 'oldest' ? 'checked' : ''; ?> onchange="this.form.submit()">
<span>Älteste Beiträge</span>
</label>
</div>
</div>
<div class="s-res-sidebar-box">
<h3 class="s-res-sidebar-title">Kategorie filtern</h3>
<select id="category-filter" class="s-res-limit-select" style="width: 100%; padding: 8px; border-radius: 6px; border: 1px solid #cbd5e1;">
<option value="all">Alle Kategorien</option>
<option value="Deutsch">Deutsch</option>
<option value="Englisch">Englisch</option>
<option value="Franzoesisch">Französisch</option>
<option value="Latein">Latein</option>
<option value="Literatur">Literatur</option>
<option value="Mathematik">Mathematik</option>
<option value="Biologie">Biologie</option>
<option value="Informatik">Informatik</option>
<option value="Chemie">Chemie</option>
<option value="Physik">Physik</option>
<option value="Astronomie">Astronomie</option>
<option value="Geschichte">Geschichte</option>
<option value="Erdkunde">Erdkunde</option>
<option value="Sozialkunde">Sozialkunde</option>
<option value="Wirtschaftskunde">Wirtschaftskunde</option>
<option value="Religion">Religion</option>
<option value="Ethikunterricht">Ethikunterricht</option>
<option value="Philosophie">Philosophie</option>
<option value="Psychologie">Psychologie</option>
<option value="Kunst">Kunst</option>
<option value="Musik">Musik</option>
<option value="Theater">Theater</option>
<option value="Technik">Technik</option>
<option value="Werken">Werken</option>
<option value="Hauswirtschaft">Hauswirtschaft</option>
<option value="Sport">Sport</option>
</select>
</div>
</form>
</aside>
@@ -119,7 +66,7 @@ $resultCount = count($results);
<div class="s-res-header">
<h1 class="s-res-main-title">Suchergebnisse</h1>
<p class="s-res-meta"><?php echo $totalResultsCount; ?> Treffer für Ihre Suchanfrage "<?php echo htmlspecialchars($query); ?>"</p>
<p class="s-res-meta"><?php echo $resultCount; ?> Treffer für Ihre Suchanfrage "<?php echo htmlspecialchars($query); ?>"</p>
</div>
<!-- Ergebnisliste -->
@@ -128,7 +75,7 @@ $resultCount = count($results);
if (!empty($results)): ?>
<?php foreach ($results as $item): ?>
<div class="s-res-item" data-likes="<?php echo $item['likes'] ?? 0; ?>" data-category="<?php echo strtolower($item['category'] ?? ''); ?>">
<div class="s-res-item">
<div class="s-res-content">
<h2 class="s-res-item-title">
<a href="index.php?pfad=showArticle&id=<?php echo $item['id']; ?>" class="s-res-link">
@@ -136,7 +83,6 @@ $resultCount = count($results);
</a>
</h2>
<p class="s-res-author">Von: <span class="s-res-author-name"><?php echo htmlspecialchars($item['author']); ?></span></p>
<p style="font-size: 0.8rem; color: #3b82f6; margin-top: 2px;">Kategorie: <?php echo htmlspecialchars($item['category'] ?? 'Allgemein'); ?></p>
</div>
<div class="s-res-arrow">&rarr;</div>
</div>
@@ -146,8 +92,8 @@ $resultCount = count($results);
elseif (isset($_SESSION["search_query"]) && $_SESSION["search_query"] !== "" && $resultCount === 0): ?>
<p>Keine Beiträge zu diesem Suchbegriff gefunden.</p>
<?php
elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "invalid_search_query"): ?>
<p>Unzulässige Suchanfrage</p>
elseif (isset($_SESSION["message"]) && $_SESSION["message"] == "missing_parameters"): ?>
<p>Bitte überprüfe deine Sucheingabe und versuche es erneut!</p>
<?php endif; ?>
<?php
@@ -169,14 +115,12 @@ $resultCount = count($results);
</div>
<div class="s-res-page-navigation">
<button type="button" class="s-res-page-btn" id="prev-page-btn" data-page="0">«</button>
<span id="dynamic-page-numbers"></span>
<button type="button" class="s-res-page-btn" id="next-page-btn" data-page="2">»</button>
<button type="button" class="s-res-page-btn" disabled>&laquo;</button>
<button type="button" class="s-res-page-btn s-res-page-btn-active">1</button>
<button type="button" class="s-res-page-btn">&raquo;</button>
</div>
</div>
</main>
</div>
</div>
+5 -102
View File
@@ -1,33 +1,11 @@
<?php
include_once 'php/controller/showArticle-controller.php';
require_once 'php/model/CommentManager.php';
$comments = [];
$mainComments = [];
$repliesByParent = [];
if (isset($_GET["id"])) {
try {
$commentManager = CommentManager::getInstance();
$comments = $commentManager->getCommentsByArticle($_GET["id"]);
foreach ($comments as $comment) {
if ($comment->isReply()) {
$parentId = $comment->getParentCommentId();
$repliesByParent[$parentId][] = $comment;
} else {
$mainComments[] = $comment;
}
}
} catch (Exception $e) {
$_SESSION["message"] = "internal_error";
}
}
?>
<!--
Seite: Anzeige für Beiträge
Funktion: Stellt einen übergebenen Beitrag dar.
-->
Seite: Anzeige für Beiträge
Funktion: Stellt einen übergebenen Beitrag dar.
-->
<!-- Hauptcontainer für die Beitragsansicht (Ausschließlich der Content-Bereich) -->
<main class="article-view-container">
<?php include_once "includes/alertMessages.php"?>
@@ -38,7 +16,6 @@ if (isset($_GET["id"])) {
<?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>
@@ -105,79 +82,5 @@ if (isset($_GET["id"])) {
</div>
<?php endif; ?>
<section class="article-comments-section">
<h2>Kommentare</h2>
</main>
<div id="comments-list">
<?php if (!empty($mainComments)): ?>
<?php foreach ($mainComments as $comment): ?>
<div class="comment-item" data-comment-id="<?php echo htmlspecialchars($comment->getId()); ?>">
<p>
<strong><?php echo htmlspecialchars($comment->getAuthor()); ?></strong>
<span><?php echo htmlspecialchars($comment->getCreated()); ?></span>
</p>
<p><?php echo nl2br(htmlspecialchars($comment->getContent())); ?></p>
<?php if (isset($_SESSION["user_email"])): ?>
<button type="button"
class="reply-button"
data-comment-id="<?php echo htmlspecialchars($comment->getId()); ?>"
data-author="<?php echo htmlspecialchars($comment->getAuthor()); ?>">
Antworten
</button>
<?php endif; ?>
<div class="comment-replies">
<?php if (isset($repliesByParent[$comment->getId()])): ?>
<?php foreach ($repliesByParent[$comment->getId()] as $reply): ?>
<div class="comment-item comment-reply">
<p>
<strong><?php echo htmlspecialchars($reply->getAuthor()); ?></strong>
<span><?php echo htmlspecialchars($reply->getCreated()); ?></span>
</p>
<p><?php echo nl2br(htmlspecialchars($reply->getContent())); ?></p>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="no-comments-message">
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"] ?? ""); ?>">
<input type="hidden"
name="parent_comment_id"
id="parent-comment-id"
value="">
<p id="reply-info" class="reply-info" style="display: none;"></p>
<textarea name="content"
id="comment-content"
placeholder="Schreibe einen Kommentar..."
required></textarea>
<button type="submit" class="button">
Kommentar senden
</button>
</form>
<?php else: ?>
<div class="comment-login-hint">
<p>Melde dich an, um einen Kommentar zu schreiben.</p>
<a href="index.php?pfad=login" class="button">Jetzt anmelden</a>
</div>
<?php endif; ?>
</section>
</main>
-93
View File
@@ -147,96 +147,3 @@
font-size: 1.85rem;
}
}
/* --- KOMMENTARE --- */
.article-comments-section {
margin-top: 3rem;
padding-top: 2rem;
border-top: 1px solid #e2e8f0;
}
.article-comments-section h2 {
font-size: 2rem;
margin-bottom: 1.5rem;
}
#comments-list {
margin-bottom: 2rem;
}
.comment-item {
background-color: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 10px;
padding: 1rem 1.25rem;
margin-bottom: 1rem;
}
#comment-form {
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
#comment-content {
width: 100%;
min-height: 130px;
padding: 1rem;
border: 1px solid #cbd5e1;
border-radius: 8px;
font-size: 1rem;
font-family: inherit;
resize: vertical;
}
#comment-form .button {
width: 100%;
}
.reply-button {
display: inline-block;
margin-top: 0.75rem;
background: none;
border: none;
color: #2563eb;
font-weight: 700;
cursor: pointer;
padding: 0;
font-size: 0.95rem;
}
.reply-button:hover {
text-decoration: underline;
}
.comment-replies {
margin-top: 1rem;
margin-left: 2rem;
padding-left: 1rem;
border-left: 3px solid #cbd5e1;
}
.comment-reply {
background-color: #eef6ff;
margin-top: 1rem;
}
.reply-info {
margin: 0.5rem 0;
color: #475569;
font-weight: 600;
}
.comment-login-hint {
margin-top: 2rem;
padding: 1.5rem;
background-color: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 10px;
text-align: center;
}
.comment-login-hint p {
margin-bottom: 1rem;
}
-10
View File
@@ -63,16 +63,6 @@
Dein Beitrag wurde erfolgreich veröffentlicht!
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "article_updated"): ?>
<p class="alert-message is-success">
Der Beitrag wurde erfolgreich bearbeitet und gespeichert.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "profile_updated"): ?>
<p class="alert-message is-success">
Das Profil wurde erfolgreich bearbeitet.
</p>
<?php endif; ?>
<?php if (isset($_SESSION["message"]) && $_SESSION["message"] == "image_upload_error"): ?>
<p class="alert-message is-error">
Das Bild konnte nicht hochgeladen werden. Bitte versuche es erneut oder verwende ein anderes Bildformat.
-5
View File
@@ -52,12 +52,7 @@ if ($pfad === "deleteAccount") {
<link rel="stylesheet" href="css/showArticle.css">
<link rel="stylesheet" href="css/message.css">
<script src="js/paginator.js" async></script>
<script src="js/sorter.js" async></script>
<script src="js/comments.js" defer></script>
<script src="js/editor.js" async></script>
<script src="js/filter.js" async></script>
<title>EduForge</title>
</head>
-137
View File
@@ -1,137 +0,0 @@
/**
* Initialisiert die Kommentarfunktion.
*
* Kommentare werden per AJAX gespeichert,
* ohne dass die Seite neu geladen werden muss.
*/
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("comment-form");
const commentsList = document.getElementById("comments-list");
const commentContent = document.getElementById("comment-content");
const parentCommentInput = document.getElementById("parent-comment-id");
const replyInfo = document.getElementById("reply-info");
if (!form || !commentsList || !commentContent || !parentCommentInput || !replyInfo) {
return;
}
/**
* Aktiviert einen einzelnen Antworten-Button.
*
* @param {HTMLButtonElement} button Antworten-Button
*/
function registerReplyButton(button) {
button.addEventListener("click", function () {
parentCommentInput.value = button.dataset.commentId;
replyInfo.textContent = "Antwort auf " + button.dataset.author;
replyInfo.style.display = "block";
commentContent.focus();
});
}
/**
* Registriert alle bereits vorhandenen Antwort-Buttons.
*/
document.querySelectorAll(".reply-button").forEach(function (button) {
registerReplyButton(button);
});
/**
* Sendet Kommentare per AJAX an den Server.
*/
form.addEventListener("submit", function (event) {
event.preventDefault();
const formData = new FormData(form);
const parentCommentId = parentCommentInput.value;
fetch("php/ajax/add-comment.php", {
method: "POST",
body: formData
})
.then(response => response.json())
.then(data => {
if (!data.success) {
alert(data.message);
return;
}
const emptyMessage = commentsList.querySelector(".no-comments-message");
if (emptyMessage) {
emptyMessage.remove();
}
const commentElement = document.createElement("div");
commentElement.classList.add("comment-item");
if (parentCommentId) {
commentElement.classList.add("comment-reply");
commentElement.innerHTML = `
<p>
<strong>${escapeHtml(data.author)}</strong>
<span>${escapeHtml(data.created)}</span>
</p>
<p>${escapeHtml(data.content).replace(/\n/g, "<br>")}</p>
`;
const parentReplies = document.querySelector(
`.comment-item[data-comment-id="${parentCommentId}"] .comment-replies`
);
if (parentReplies) {
parentReplies.appendChild(commentElement);
}
} else {
commentElement.dataset.commentId = data.commentId;
commentElement.innerHTML = `
<p>
<strong>${escapeHtml(data.author)}</strong>
<span>${escapeHtml(data.created)}</span>
</p>
<p>${escapeHtml(data.content).replace(/\n/g, "<br>")}</p>
<button type="button"
class="reply-button"
data-comment-id="${escapeHtml(data.commentId)}"
data-author="${escapeHtml(data.author)}">
Antworten
</button>
<div class="comment-replies"></div>
`;
commentsList.prepend(commentElement);
const newReplyButton = commentElement.querySelector(".reply-button");
if (newReplyButton) {
registerReplyButton(newReplyButton);
}
}
commentContent.value = "";
parentCommentInput.value = "";
replyInfo.textContent = "";
replyInfo.style.display = "none";
})
.catch(() => {
alert("Kommentar konnte nicht gesendet werden.");
});
});
/**
* Entfernt HTML-Sonderzeichen aus Nutzereingaben.
*
* @param {string} text Zu bereinigender Text
* @returns {string} Sicherer Text
*/
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
});
-101
View File
@@ -1,101 +0,0 @@
let currentClientPage = 1;
const itemsPerPage = 10;
function initFilter() {
const filterSelect = document.getElementById('category-filter');
const listContainer = document.querySelector('.s-res-list');
if (!filterSelect || !listContainer) return;
updateVisibility();
filterSelect.addEventListener('change', function() {
currentClientPage = 1;
updateVisibility();
});
const navigationContainer = document.querySelector('.s-res-page-navigation');
if (navigationContainer) {
navigationContainer.addEventListener('click', function(e) {
const button = e.target.closest('.s-res-page-btn');
if (!button || button.disabled) return;
e.preventDefault();
const targetPage = button.getAttribute('data-page');
if (targetPage) {
currentClientPage = parseInt(targetPage, 10);
updateVisibility();
}
});
}
}
function updateVisibility() {
const filterSelect = document.getElementById('category-filter');
const listContainer = document.querySelector('.s-res-list');
const selectedCategory = filterSelect.value.toLowerCase().trim();
const cards = listContainer.querySelectorAll('.s-res-item');
let visibleCards = [];
cards.forEach(card => {
const cardCategory = (card.getAttribute('data-category') || '').toLowerCase().trim();
if (selectedCategory === 'all' || cardCategory.includes(selectedCategory) || selectedCategory.includes(cardCategory)) {
visibleCards.push(card);
} else {
card.style.display = 'none';
}
});
const totalVisible = visibleCards.length;
const totalPages = Math.max(1, Math.ceil(totalVisible / itemsPerPage));
if (currentClientPage < 1) currentClientPage = 1;
if (currentClientPage > totalPages) currentClientPage = totalPages;
const startOffset = (currentClientPage - 1) * itemsPerPage;
const endOffset = startOffset + itemsPerPage;
visibleCards.forEach((card, index) => {
if (index >= startOffset && index < endOffset) {
card.style.display = 'flex';
} else {
card.style.display = 'none';
}
});
updatePaginatorUI(currentClientPage, totalPages);
}
function updatePaginatorUI(currentPage, totalPages) {
const prevBtn = document.getElementById('prev-page-btn');
const nextBtn = document.getElementById('next-page-btn');
const numbersContainer = document.getElementById('dynamic-page-numbers');
if (!prevBtn || !nextBtn || !numbersContainer) return;
prevBtn.setAttribute('data-page', currentPage - 1);
prevBtn.disabled = (currentPage <= 1);
nextBtn.setAttribute('data-page', currentPage + 1);
nextBtn.disabled = (currentPage >= totalPages);
let buttonsHTML = '';
for (let i = 1; i <= totalPages; i++) {
const activeClass = (i === currentPage) ? 's-res-page-btn-active' : '';
buttonsHTML += `<button type="button" class="s-res-page-btn ${activeClass}" data-page="${i}">${i}</button> `;
}
numbersContainer.innerHTML = buttonsHTML;
}
// Hilfsfunktion für Math.ceil in JS
function ceil(val) { return Math.ceil(val); }
// ist das DOM bereits vollständig aufgebaut?
if (document.readyState === 'loading') {
// Falls noch geladen wird, auf das Event warten
document.addEventListener('DOMContentLoaded', initFilter);
} else {
// Falls das HTML bereits komplett da ist, sofort ausführen
initFilter();
}
-27
View File
@@ -1,27 +0,0 @@
function initPaginator() {
const form = document.getElementById('search-form-id');
const pageInput = document.getElementById('s-res-page-input');
const pageButtons = document.querySelectorAll('.s-res-page-navigation .s-res-page-btn');
pageButtons.forEach(button => {
button.addEventListener('click', function() {
if (this.disabled) return;
const targetPage = this.getAttribute('data-page');
if (targetPage && form && pageInput) {
pageInput.value = targetPage;
form.submit();
}
});
});
}
// ist das DOM bereits vollständig aufgebaut?
if (document.readyState === 'loading') {
// Falls noch geladen wird, auf das Event warten
document.addEventListener('DOMContentLoaded', initPaginator);
} else {
// Falls das HTML bereits komplett da ist, sofort ausführen
initPaginator();
}
-50
View File
@@ -1,50 +0,0 @@
function initSorter() {
const listContainer = document.querySelector('.s-res-list');
const sortRadios = document.querySelectorAll('.sort-radio');
// wenn keine liste vorhanden, abbrechen
if (!listContainer || sortRadios.length === 0) return;
sortRadios.forEach(radio => {
radio.addEventListener('change', function() {
const cards = Array.from(listContainer.querySelectorAll('.s-res-item'));
const sortValue = this.value;
cards.sort((a, b) => {
if (sortValue === 'likes') {
const likesA = parseInt(a.getAttribute('data-likes') || '0', 10);
const likesB = parseInt(b.getAttribute('data-likes') || '0', 10);
return likesB - likesA;
}
else if (sortValue === 'alphabet') {
// alphabetische sortierung
const titleA = a.querySelector('.s-res-link').textContent.trim().toLowerCase();
const titleB = b.querySelector('.s-res-link').textContent.trim().toLowerCase();
return titleA.localeCompare(titleB);
}
else if (sortValue === 'newest' || sortValue === 'oldest') {
// hoehere ID wird als neuer gesehen
const urlA = a.querySelector('.s-res-link').getAttribute('href');
const urlB = b.querySelector('.s-res-link').getAttribute('href');
const idA = parseInt(urlA.match(/id=(\d+)/)[1], 10);
const idB = parseInt(urlB.match(/id=(\d+)/)[1], 10);
return sortValue === 'newest' ? idB - idA : idA - idB;
}
return 0;
});
listContainer.innerHTML = '';
cards.forEach(card => listContainer.appendChild(card));
});
});
}
// ist das DOM bereits vollständig aufgebaut?
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initSorter);
} else {
initSorter();
}
-58
View File
@@ -1,58 +0,0 @@
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
header("Content-Type: application/json");
require_once "../model/CommentManager.php";
if (!isset($_SESSION["user_email"])) {
echo json_encode([
"success" => false,
"message" => "Du musst angemeldet sein, um zu kommentieren."
]);
exit();
}
$articleId = $_POST["article_id"] ?? null;
$content = trim($_POST["content"] ?? "");
$parentCommentId = $_POST["parent_comment_id"] ?? null;
if ($parentCommentId === "" || $parentCommentId === "0") {
$parentCommentId = null;
}
if (empty($articleId) || empty($content)) {
echo json_encode([
"success" => false,
"message" => "Kommentar darf nicht leer sein."
]);
exit();
}
try {
$commentManager = CommentManager::getInstance();
$commentId = $commentManager->addComment(
$articleId,
$_SESSION["user_email"],
$content,
$parentCommentId
);
echo json_encode([
"success" => true,
"commentId" => $commentId,
"author" => $_SESSION["user_email"],
"content" => $content,
"created" => date("Y-m-d H:i:s"),
"parentCommentId" => $parentCommentId
]);
} catch (Exception $e) {
echo json_encode([
"success" => false,
"message" => "Kommentar konnte nicht gespeichert werden."
]);
}
@@ -6,10 +6,6 @@ require_once '../model/LocalArticleManager.php';
require_once '../model/ArticleManager.php';
require_once '../validator/article-validator.php';
if (!isset($_SESSION["user"])) {
header("Location: index.php?pfad=login");
exit();
}
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$_SESSION["old_title"] = $_POST["title"] ?? '';
$_SESSION["old_content"] = $_POST["content"] ?? '';
@@ -6,11 +6,6 @@ if (session_status() === PHP_SESSION_NONE) {
require_once __DIR__ . "/../model/UserManager.php";
require_once __DIR__ . "/../model/ArticleManager.php";
if (!isset($_SESSION["user"])) {
header("Location: index.php?pfad=login");
exit();
}
/*
Deregistrierung
Funktion: Entfernt User aus der Datenbank und beendet die Session
@@ -5,11 +5,6 @@ if (session_status() === PHP_SESSION_NONE) {
require_once __DIR__ . "/../model/ArticleManager.php";
if (!isset($_SESSION["user"])) {
header("Location: index.php?pfad=login");
exit();
}
if ($_SERVER["REQUEST_METHOD"] === "POST") {
if (isset($_SESSION["user_email"])) {
+5 -35
View File
@@ -6,44 +6,14 @@ require_once 'php/model/Article.php';
require_once 'php/model/ArticleManager.php';
require_once 'php/model/LocalArticleManager.php';
$categoriesWithArticles = [];
$allowedCategories = [
'deutsch', 'englisch', 'franzoesisch', 'latein', 'literatur',
'mathe', 'biologie', 'chemie', 'physik', 'informatik', 'astronomie',
'geschichte', 'erdkunde', 'sozialkunde', 'wirtschaft', 'religion',
'ethik', 'philosophie', 'psychologie', 'kunst', 'musik', 'theater',
'technik', 'werken', 'hauswirtschaft', 'sport'
];
try {
$articleManager = ArticleManager::getInstance();
foreach ($allowedCategories as $categorySlug) {
$allCategoryArticles = $articleManager->getArticlesByCategory($categorySlug);
// nur Kategorien, die Beiträge enthält:
if (!empty($allCategoryArticles) && is_array($allCategoryArticles)) {
// Beiträge nach Erstellungsdatum sortieren:
usort($allCategoryArticles, function($a, $b) {
$dateA = strtotime($a->getCreationDate());
$dateB = strtotime($b->getCreationDate());
return $dateB <=> $dateA; // Absteigende Sortierung
});
// auf die 5 zuletzt hinzugefügten Beiträge begrenzen:
$limitedArticles = array_slice($allCategoryArticles, 0, 5);
$categoriesWithArticles[] = [
'slug' => $categorySlug,
'name' => ucfirst($categorySlug), // Erster Buchstabe groß für die Ansicht
'articles' => $limitedArticles
];
}
}
// Beziehen der Dummy-Beiträge aus dem ArticleManager:
$dummy1 = $articleManager->getArticle(1);
$dummy2 = $articleManager->getArticle(2);
$dummy3 = $articleManager->getArticle(3);
} catch (Exception $e){
$_SESSION["message"] = "internal_error";
echo "Fehler aufgetreten: " . $e->getMessage();
}
?>
-5
View File
@@ -3,7 +3,6 @@
require_once "php/model/UserManager.php";
require_once "php/model/Article.php";
require_once "php/model/ArticleManager.php";
require_once "php/model/CommentManager.php";
require_once "php/validator/user-validator.php";
$error = null;
@@ -63,7 +62,6 @@ try {
$_SESSION["user"] = $vorname . " " . $nachname;
$_SESSION["user_email"] = $newEmail;
$_SESSION["message"] = "profile_updated";
header("Location: index.php?pfad=profile");
exit();
} else {
@@ -78,9 +76,6 @@ try {
$articleManager = ArticleManager::getInstance();
$userArticles = $articleManager->getArticlesByAuthor($_SESSION["user_email"]);
$commentManager = CommentManager::getInstance();
$userComments = $commentManager->getCommentsByAuthor($_SESSION["user_email"]);
if (!isset($userArticles)) {
$_SESSION["message"] = "user_has_no_articles";
}
+3 -12
View File
@@ -5,15 +5,14 @@ if (session_status() === PHP_SESSION_NONE) {
require_once '../model/LocalArticleManager.php';
require_once '../model/ArticleManager.php';
require_once '../model/Article.php';
require_once '../validator/search-validator.php';
if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
$search = trim($_GET["q"]);
if (!searchQueryValidator($search)) {
if (empty($search)) {
$_SESSION["search_results"] = [];
$_SESSION["search_query"] = "";
$_SESSION["message"] = "invalid_search_query";
$_SESSION["message"] = "missing_parameters";
} else {
try {
@@ -52,7 +51,6 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
"category" => $obj->category,
"tags" => $obj->tags,
"creationDate" => $obj->creationDate
//"likes" => $obj->likes
];
}
@@ -64,14 +62,7 @@ if ($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["q"])) {
$_SESSION["message"] = "internal_error";
}
}
$sort = $_GET['sort'] ?? 'alphabet';
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 10;
if (!searchLimitValidator($limit)) {
$limit = 10;
}
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
header("Location: ../../index.php?pfad=search-results&q=" . urlencode($search) . "&sort=" . urlencode($sort) . "&limit=" . $limit . "&page=" . $page);
header("Location: ../../index.php?pfad=search-results");
exit();
}
@@ -8,11 +8,6 @@ require_once '../model/ArticleManager.php';
require_once '../model/Article.php';
require_once '../validator/article-validator.php';
if (!isset($_SESSION["user"])) {
header("Location: index.php?pfad=login");
exit();
}
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$_SESSION["old_title"] = $_POST["title"] ?? '';
$_SESSION["old_content"] = $_POST["content"] ?? '';
@@ -27,20 +22,6 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
exit();
}
try {
$articleManager = ArticleManager::getInstance();
$article = $articleManager->getArticle($id);
if ($article->getAuthor() != $_SESSION["user"]->getUsername()) {
$_SESSION["message"] = "unauthorized_access";
header("location: ../../index.php");
exit();
}
} catch (Exception $e) {
$_SESSION["message"] = $e->getMessage();
header("location: ../../index.php?pfad=updateArticle&id=$id");
exit();
}
if (!isset($_POST["title"]) ||!isset($_POST["content"]) || !isset($_POST["category"])){
$_SESSION["message"] = "missing_parameters";
header("location: ../../index.php?pfad=updateArticle&id=$id");
-115
View File
@@ -1,115 +0,0 @@
<?php
/**
* Repräsentiert einen Kommentar unter einem Beitrag.
*
* Ein Kommentar kann entweder ein Hauptkommentar sein
* oder eine Antwort auf einen anderen Kommentar.
*
* @author Caroline Schulte
*/
class Comment
{
private int $id;
private int $articleId;
private ?int $parentCommentId;
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 int|null $parentCommentId ID des Eltern-Kommentars oder null
* @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,
?int $parentCommentId,
string $author,
string $content,
string $created
) {
$this->id = $id;
$this->articleId = $articleId;
$this->parentCommentId = $parentCommentId;
$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 die ID des Eltern-Kommentars zurück.
*
* @return int|null ID des Eltern-Kommentars oder null
*/
public function getParentCommentId(): ?int
{
return $this->parentCommentId;
}
/**
* Gibt zurück, ob der Kommentar eine Antwort ist.
*
* @return bool true wenn der Kommentar eine Antwort ist, sonst false
*/
public function isReply(): bool
{
return $this->parentCommentId !== null && $this->parentCommentId !== 0;
}
/**
* 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
@@ -1,25 +0,0 @@
<?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();
}
}
-54
View File
@@ -1,54 +0,0 @@
<?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.
*
* Optional kann eine parentCommentId übergeben werden,
* wenn der Kommentar eine Antwort auf einen anderen Kommentar ist.
*
* @param int $articleId ID des Beitrags
* @param string $author Autor des Kommentars
* @param string $content Inhalt des Kommentars
* @param int|null $parentCommentId ID des Eltern-Kommentars oder null
*
* @return int ID des neu gespeicherten Kommentars
*/
public function addComment(
$articleId,
$author,
$content,
$parentCommentId = null
);
/**
* Gibt alle Kommentare eines Beitrags zurück.
*
* @param int $articleId ID des Beitrags
*
* @return Comment[] Liste der Kommentare
*/
public function getCommentsByArticle(
$articleId
);
/**
* Gibt alle Kommentare eines Autors zurück.
*
* @param string $author E-Mail-Adresse des Autors
*
* @return Comment[] Liste der Kommentare
*/
public function getCommentsByAuthor($author);
}
-257
View File
@@ -1,257 +0,0 @@
<?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,
parent_comment_id INTEGER NULL,
author TEXT NOT NULL,
content TEXT NOT NULL,
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
");
$columns = $db->query("PRAGMA table_info(comments);")->fetchAll(PDO::FETCH_ASSOC);
$hasParentColumn = false;
foreach ($columns as $column) {
if ($column["name"] === "parent_comment_id") {
$hasParentColumn = true;
break;
}
}
if (!$hasParentColumn) {
$db->exec("ALTER TABLE comments ADD COLUMN parent_comment_id INTEGER NULL;");
}
} catch (PDOException $e) {
throw new RuntimeException("internal_error");
}
}
/**
* Baut die Verbindung zur SQLite-Datenbank auf.
*
* @return PDO Datenbankverbindung
*/
private function getConnection()
{
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("internal_error");
}
}
/**
* Gibt die Singleton-Instanz zurück.
*
* @return DatabaseCommentManager
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new DatabaseCommentManager();
}
return self::$instance;
}
/**
* Speichert einen neuen Kommentar oder eine Antwort.
*
* @param int $articleId ID des Beitrags
* @param string $author Autor des Kommentars
* @param string $content Inhalt des Kommentars
* @param int|null $parentCommentId ID des Eltern-Kommentars oder null
*
* @return int ID des neu gespeicherten Kommentars
*/
public function addComment(
$articleId,
$author,
$content,
$parentCommentId = null
) {
try {
$db = $this->getConnection();
if ($parentCommentId === "" || $parentCommentId === 0 || $parentCommentId === "0") {
$parentCommentId = null;
}
$sql = "
INSERT INTO comments (
article_id,
parent_comment_id,
author,
content
)
VALUES (
:articleId,
:parentCommentId,
:author,
:content
)
";
$command = $db->prepare($sql);
$command->execute([
":articleId" => $articleId,
":parentCommentId" => $parentCommentId,
":author" => $author,
":content" => $content
]);
return intval($db->lastInsertId());
} catch (PDOException $e) {
throw new RuntimeException("internal_error");
}
}
/**
* Lädt alle Kommentare eines Beitrags.
*
* @param int $articleId ID des Beitrags
*
* @return Comment[]
*/
public function getCommentsByArticle($articleId)
{
try {
$db = $this->getConnection();
$sql = "
SELECT
id,
article_id,
CASE
WHEN parent_comment_id IS NULL THEN NULL
WHEN parent_comment_id = '' THEN NULL
WHEN parent_comment_id = 0 THEN NULL
ELSE parent_comment_id
END AS parent_comment_id,
author,
content,
created
FROM comments
WHERE article_id = :articleId
ORDER BY created ASC
";
$command = $db->prepare($sql);
$command->execute([":articleId" => $articleId]);
return $this->mapRowsToComments($command);
} catch (PDOException $e) {
throw new RuntimeException("internal_error");
}
}
/**
* Lädt alle Kommentare eines Autors.
*
* @param string $author E-Mail-Adresse des Autors
*
* @return Comment[]
*/
public function getCommentsByAuthor($author)
{
try {
$db = $this->getConnection();
$sql = "
SELECT
id,
article_id,
CASE
WHEN parent_comment_id IS NULL THEN NULL
WHEN parent_comment_id = '' THEN NULL
WHEN parent_comment_id = 0 THEN NULL
ELSE parent_comment_id
END AS parent_comment_id,
author,
content,
created
FROM comments
WHERE author = :author
ORDER BY created DESC
";
$command = $db->prepare($sql);
$command->execute([":author" => $author]);
return $this->mapRowsToComments($command);
} catch (PDOException $e) {
throw new RuntimeException("internal_error");
}
}
/**
* Wandelt Datenbankzeilen in Comment-Objekte um.
*
* @param PDOStatement $command Ausgeführtes Statement
*
* @return Comment[]
*/
private function mapRowsToComments($command)
{
$comments = [];
while ($row = $command->fetch(PDO::FETCH_ASSOC)) {
$parentCommentId = null;
if (
isset($row["parent_comment_id"])
&& $row["parent_comment_id"] !== null
&& $row["parent_comment_id"] !== ""
&& intval($row["parent_comment_id"]) !== 0
) {
$parentCommentId = intval($row["parent_comment_id"]);
}
$comments[] = new Comment(
intval($row["id"]),
intval($row["article_id"]),
$parentCommentId,
$row["author"],
$row["content"],
$row["created"]
);
}
return $comments;
}
}
-40
View File
@@ -1,40 +0,0 @@
<?php
/**
* Prüft, ob eine Suchanfrage gültig ist.
*
* Erlaubt werden Buchstaben, Zahlen, Umlaute, typische Satzzeichen und Leerzeichen.
* Die Länge muss zwischen 1 und 50 Zeichen liegen.
*
* @param string $query Zu prüfender Suchbegriff
*
* @return bool true wenn die Suche gültig ist, sonst false
*/
function searchQueryValidator($query)
{
$query = trim($query);
// Mindestens 1 Zeichen, maximal 50 Zeichen
$length = mb_strlen($query);
if ($length < 1 || $length > 50) {
return false;
}
// Erlaubt Buchstaben (inkl. Umlaut/ß), Zahlen, Leerzeichen sowie ?, !, ., -, _
$searchPattern = '/^[a-zA-Z0-9äöüÄÖÜß\s?!.,\-_]+$/u';
return preg_match($searchPattern, $query) === 1;
}
/**
* Prüft, ob das gewählte Treffer-Limit erlaubt ist.
*
* @param int|string $limit Das zu prüfende Limit
*
* @return bool true wenn das Limit 10, 20, 50 oder 100 ist, sonst false
*/
function searchLimitValidator($limit)
{
$allowedLimits = [10, 20, 50, 100];
return in_array((int)$limit, $allowedLimits, true);
}