跳到內容

高級模塊示例

一個綜合的”論壇”模塊,展示高級模式:多個實體類型、關係、複雜管理界面和通知。

forum/
├── xoops_version.php
├── class/
│ ├── Repository/
│ │ ├── ForumRepository.php
│ │ ├── TopicRepository.php
│ │ └── PostRepository.php
│ ├── Entity/
│ │ ├── Forum.php
│ │ ├── Topic.php
│ │ └── Post.php
│ ├── Service/
│ │ ├── ForumService.php
│ │ └── TopicService.php
│ └── Handler/
│ └── NotificationHandler.php
├── templates/
│ ├── forum_list.html
│ ├── topic_view.html
│ └── admin/dashboard.html
└── sql/mysql.sql
-- 論壇
CREATE TABLE `xoops_forum_forums` (
`forum_id` INT AUTO_INCREMENT PRIMARY KEY,
`forum_name` VARCHAR(255) NOT NULL,
`forum_description` TEXT,
`forum_order` INT,
`forum_created` INT NOT NULL
);
-- 主題
CREATE TABLE `xoops_forum_topics` (
`topic_id` INT AUTO_INCREMENT PRIMARY KEY,
`topic_forum_id` INT NOT NULL,
`topic_author_id` INT NOT NULL,
`topic_title` VARCHAR(255) NOT NULL,
`topic_post_count` INT DEFAULT 1,
`topic_view_count` INT DEFAULT 0,
`topic_created` INT NOT NULL,
FOREIGN KEY (`topic_forum_id`) REFERENCES `xoops_forum_forums`(`forum_id`)
);
-- 帖子
CREATE TABLE `xoops_forum_posts` (
`post_id` INT AUTO_INCREMENT PRIMARY KEY,
`post_topic_id` INT NOT NULL,
`post_forum_id` INT NOT NULL,
`post_author_id` INT NOT NULL,
`post_content` LONGTEXT NOT NULL,
`post_created` INT NOT NULL,
FOREIGN KEY (`post_topic_id`) REFERENCES `xoops_forum_topics`(`topic_id`)
);
-- 訂閱
CREATE TABLE `xoops_forum_subscriptions` (
`subscription_id` INT AUTO_INCREMENT PRIMARY KEY,
`subscription_user_id` INT NOT NULL,
`subscription_topic_id` INT NOT NULL,
UNIQUE (`subscription_user_id`, `subscription_topic_id`)
);
<?php
class Topic
{
private $id;
private $forumId;
private $authorId;
private $title;
private $postCount = 1;
private $viewCount = 0;
private $createdAt;
// Getters and setters...
public function getId() { return $this->id; }
public function setId($id) { $this->id = $id; return $this; }
public function getForumId() { return $this->forumId; }
public function setForumId($id) { $this->forumId = $id; return $this; }
public function getTitle() { return $this->title; }
public function setTitle($t) { $this->title = $t; return $this; }
public function getPostCount() { return $this->postCount; }
public function incrementPostCount() { $this->postCount++; return $this; }
public function getViewCount() { return $this->viewCount; }
public function incrementViewCount() { $this->viewCount++; return $this; }
}
?>
<?php
class TopicRepository
{
private $db;
public function __construct($connection)
{
$this->db = $connection;
}
public function getWithAuthorInfo($id)
{
$sql = "SELECT t.*, u.uname as author_name
FROM " . $this->db->prefix('forum_topics') . " t
LEFT JOIN " . $this->db->prefix('users') . " u
ON t.topic_author_id = u.uid
WHERE t.topic_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('i', $id);
$stmt->execute();
return $stmt->get_result()->fetch_assoc();
}
public function getByForumWithStats($forumId, $limit = 20, $offset = 0)
{
$sql = "SELECT t.*, u.uname as author_name,
COUNT(p.post_id) as post_count
FROM " . $this->db->prefix('forum_topics') . " t
LEFT JOIN " . $this->db->prefix('users') . " u
ON t.topic_author_id = u.uid
LEFT JOIN " . $this->db->prefix('forum_posts') . " p
ON t.topic_id = p.post_topic_id
WHERE t.topic_forum_id = ?
GROUP BY t.topic_id
ORDER BY t.topic_created DESC
LIMIT ?, ?";
$stmt = $this->db->prepare($sql);
$stmt->bind_param('iii', $forumId, $offset, $limit);
$stmt->execute();
$result = $stmt->get_result();
$topics = [];
while ($row = $result->fetch_assoc()) {
$topics[] = $row;
}
return $topics;
}
}
?>
<?php
class TopicService
{
private $topicRepository;
private $postRepository;
private $notificationHandler;
public function __construct(
TopicRepository $topicRepository,
PostRepository $postRepository,
NotificationHandler $notificationHandler
) {
$this->topicRepository = $topicRepository;
$this->postRepository = $postRepository;
$this->notificationHandler = $notificationHandler;
}
public function createTopic($forumId, $userId, $title, $content)
{
// 驗證
if (strlen($title) < 3) {
throw new \InvalidArgumentException('Title too short');
}
// 創建主題
$topic = new Topic();
$topic->setForumId($forumId)
->setAuthorId($userId)
->setTitle($title)
->setCreatedAt(new \DateTime());
$topicId = $this->topicRepository->save($topic);
// 創建第一個帖子
$this->postRepository->createPost($topicId, $forumId, $userId, $content);
// 通知訂閱者
$this->notificationHandler->notifyNewTopic($topicId);
return $topicId;
}
public function getTopicWithPosts($topicId, $page = 1, $perPage = 20)
{
// 獲取具有作者信息的主題
$topic = $this->topicRepository->getWithAuthorInfo($topicId);
if (!$topic) {
throw new \RuntimeException('Topic not found');
}
// 增加視圖計數
$topic['topic_view_count']++;
$this->topicRepository->updateViewCount($topicId, $topic['topic_view_count']);
// 獲取帖子
$offset = ($page - 1) * $perPage;
$posts = $this->postRepository->getByTopicId($topicId, $perPage, $offset);
return [
'topic' => $topic,
'posts' => $posts,
'page' => $page,
'totalPages' => ceil($topic['topic_post_count'] / $perPage),
];
}
}
?>

此示例演示:

  1. 實體關係 - 論壇包含主題,主題包含帖子
  2. 複雜查詢 - 帶有用戶信息和統計數據的連接
  3. Service 協調 - 多個服務協同工作
  4. 數據聚合 - 帖子計數、視圖計數
  5. 通知 - 訂閱的事件驅動通知
  6. 類似事務的操作 - 創建帶有初始帖子的主題

另見:

  • ../Patterns/Repository-Pattern 用於複雜查詢
  • ../Patterns/Service-Layer 用於服務協調
  • ../Patterns/DTO-Pattern 用於數據傳輸

標籤: #examples #advanced-module #complex-example #relationships #module-development