Skip to content

XOOPS Event System

2.5.x: Preloads 4.0.x: PSR-14

The XOOPS event system enables loose coupling between modules through an observer pattern. Components can emit events that other parts of the system can listen to and respond to.

EventTrigger Point
core.header.startBefore header processing
core.header.endAfter header processing
core.footer.startBefore footer rendering
core.footer.endAfter footer rendering
core.exceptionWhen exception occurs
EventTrigger Point
module.installAfter module installation
module.updateAfter module update
module.uninstallBefore module removal
module.activateWhen module activated
module.deactivateWhen module deactivated
EventTrigger Point
user.loginAfter successful login
user.logoutAfter logout
user.registerAfter registration
user.deleteBefore user deletion
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. Immutable Events - Events should be read-only
  2. Specific Events - Create specific events, not generic ones
  3. Async When Possible - Use queues for slow operations
  4. No Side Effects in Dispatch - Dispatch should be quick
  5. Document Events - List available events for module users