wazum / slug-cascade-contracts
PSR-14 event interface for slug-cascade situations.
Requires
- php: ^8.1
- psr/event-dispatcher: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.65
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^10.5 || ^11.0
- vimeo/psalm: ^5.26 || ^6.0
README
PSR-14 event interface for slug-cascade situations.
An interface-only package. A producer dispatches an event implementing the interface when a parent page's slug has been (or is about to be) changed and descendants need their slugs adjusted. A consumer subscribes to the interface and can short-circuit synchronous propagation by calling deferCascade().
Install
composer require wazum/slug-cascade-contracts
PHP 8.1+. No framework dependency; works with any PSR-14 event dispatcher (TYPO3 v12/v13/v14, Symfony, Laminas, …).
The contract
namespace Wazum\SlugCascadeContracts; use Psr\EventDispatcher\StoppableEventInterface; interface SlugCascadeEvent extends StoppableEventInterface { public function getPageId(): int; public function getOldParentSlug(): string; public function getNewParentSlug(): string; public function getCorrelationId(): string; public function deferCascade(): void; }
deferCascade() flips isPropagationStopped() to true. The dispatch site reads that flag and skips its own synchronous cascade when a consumer has taken over.
Producer side
namespace Acme\Producer\Event; use Wazum\SlugCascadeContracts\SlugCascadeEvent; final class SlugChanged implements SlugCascadeEvent { private bool $cascadeDeferred = false; public function __construct( public readonly int $pageId, public readonly string $oldParentSlug, public readonly string $newParentSlug, public readonly string $correlationId, ) {} public function getPageId(): int { return $this->pageId; } public function getOldParentSlug(): string { return $this->oldParentSlug; } public function getNewParentSlug(): string { return $this->newParentSlug; } public function getCorrelationId(): string { return $this->correlationId; } public function deferCascade(): void { $this->cascadeDeferred = true; } public function isPropagationStopped(): bool { return $this->cascadeDeferred; } }
Dispatch site:
$event = new SlugChanged($pageId, $oldSlug, $newSlug, $correlationId); $this->eventDispatcher->dispatch($event); if ($event->isPropagationStopped()) { return; } $this->rebuildChildSlugsSynchronously(...);
Consumer side
namespace Acme\Consumer\EventListener; use Wazum\SlugCascadeContracts\SlugCascadeEvent; final class HandleCascade { public function __invoke(SlugCascadeEvent $event): void { // … handle the cascade … $event->deferCascade(); } }
Service registration (TYPO3):
Acme\Consumer\EventListener\HandleCascade: tags: - name: event.listener event: Wazum\SlugCascadeContracts\SlugCascadeEvent
License
GPL-2.0-or-later