跳到內容

XOOPS 事件系統

2.5.x: 預加載 4.0.x: PSR-14

XOOPS 事件系統透過觀察者模式實現模組之間的鬆散耦合。元件可以發出其他部分系統可以偵聽和回應的事件。

事件觸發點
core.header.start頁首處理前
core.header.end頁首處理後
core.footer.start頁尾呈現前
core.footer.end頁尾呈現後
core.exception發生異常時
事件觸發點
module.install模組安裝後
module.update模組更新後
module.uninstall模組移除前
module.activate啟用模組時
module.deactivate停用模組時
事件觸發點
user.login成功登錄後
user.logout登出後
user.register註冊後
user.delete使用者刪除前
class/Preload.php
<?php
namespace XoopsModules\MyModule;
use Xmf\Module\Helper\AbstractHelper;
final class Preload extends AbstractHelper
{
public function eventCoreHeaderStart(array $args): void
{
// 在每個頁面的頁首前執行
}
public function eventCoreFooterStart(array $args): void
{
// 在頁尾呈現前執行
}
public function eventUserLogin(array $args): void
{
$userId = $args['userid'];
// 處理登錄事件
}
public function eventCoreException(array $args): void
{
$exception = $args['exception'];
// 記錄或處理異常
}
}
event{Category}{Action}
示例:
- eventCoreHeaderStart
- eventUserLogin
- eventModuleNewsArticleCreate
<?php
declare(strict_types=1);
namespace XoopsModules\MyModule\Event;
final class ArticleCreatedEvent
{
public function __construct(
public readonly int $articleId,
public readonly int $authorId,
public readonly string $title,
public readonly \DateTimeImmutable $createdAt
) {}
}
use Psr\EventDispatcher\EventDispatcherInterface;
final class ArticleService
{
public function __construct(
private readonly ArticleRepository $repository,
private readonly EventDispatcherInterface $dispatcher
) {}
public function create(CreateArticleDTO $dto): Article
{
$article = Article::create($dto);
$this->repository->save($article);
// 發派事件
$this->dispatcher->dispatch(new ArticleCreatedEvent(
articleId: $article->getId(),
authorId: $article->getAuthorId(),
title: $article->getTitle(),
createdAt: new \DateTimeImmutable()
));
return $article;
}
}
<?php
declare(strict_types=1);
namespace XoopsModules\MyModule\Listener;
use XoopsModules\MyModule\Event\ArticleCreatedEvent;
final class SendNotificationOnArticleCreated
{
public function __construct(
private readonly NotificationService $notifications
) {}
public function __invoke(ArticleCreatedEvent $event): void
{
$this->notifications->notifySubscribers(
'new_article',
[
'article_id' => $event->articleId,
'title' => $event->title,
]
);
}
}
config/events.php
return [
ArticleCreatedEvent::class => [
SendNotificationOnArticleCreated::class,
UpdateSearchIndex::class,
ClearArticleCache::class,
],
ArticleUpdatedEvent::class => [
UpdateSearchIndex::class,
ClearArticleCache::class,
],
ArticleDeletedEvent::class => [
RemoveFromSearchIndex::class,
ClearArticleCache::class,
],
];
use Psr\EventDispatcher\StoppableEventInterface;
final class ArticlePublishingEvent implements StoppableEventInterface
{
private bool $propagationStopped = false;
private ?string $rejectionReason = null;
public function __construct(
public readonly Article $article
) {}
public function isPropagationStopped(): bool
{
return $this->propagationStopped;
}
public function reject(string $reason): void
{
$this->propagationStopped = true;
$this->rejectionReason = $reason;
}
public function getRejectionReason(): ?string
{
return $this->rejectionReason;
}
}
// 偵聽器可以停止傳播
final class ContentModerationListener
{
public function __invoke(ArticlePublishingEvent $event): void
{
if ($this->containsProhibitedContent($event->article)) {
$event->reject('Content violates community guidelines');
}
}
}
  1. 不可變事件 - 事件應該是唯讀的
  2. 特定事件 - 建立特定事件,而不是通用事件
  3. 盡可能非同步 - 使用佇列進行緩慢操作
  4. 發派中無副作用 - 發派應該很快
  5. 記錄事件 - 為模組使用者列出可用事件