콘텐츠로 이동

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
{
// Runs on every page before header
}
public function eventCoreFooterStart(array $args): void
{
// Runs before footer renders
}
public function eventUserLogin(array $args): void
{
$userId = $args['userid'];
// Handle login event
}
public function eventCoreException(array $args): void
{
$exception = $args['exception'];
// Log or handle exception
}
}
event{Category}{Action}
Examples:
- 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);
// Dispatch event
$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;
}
}
// Listener can stop propagation
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. 문서 이벤트 - 모듈 사용자가 사용할 수 있는 이벤트를 나열합니다.