diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 6a8430cd7e77..2926da4e6428 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * Add method `getEnabledTransition()` to `WorkflowInterface` * Automatically register places from transitions * Add support for workflows that need to store many tokens in the marking + * Add method `getName()` in event classes to build event names in subscribers 7.0 --- diff --git a/src/Symfony/Component/Workflow/Event/AnnounceEvent.php b/src/Symfony/Component/Workflow/Event/AnnounceEvent.php index 0c675a4854dc..0bff3dca9133 100644 --- a/src/Symfony/Component/Workflow/Event/AnnounceEvent.php +++ b/src/Symfony/Component/Workflow/Event/AnnounceEvent.php @@ -17,6 +17,9 @@ final class AnnounceEvent extends Event { + use EventNameTrait { + getNameForTransition as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Event/CompletedEvent.php b/src/Symfony/Component/Workflow/Event/CompletedEvent.php index 63a5e44836b2..885826f151fd 100644 --- a/src/Symfony/Component/Workflow/Event/CompletedEvent.php +++ b/src/Symfony/Component/Workflow/Event/CompletedEvent.php @@ -17,6 +17,9 @@ final class CompletedEvent extends Event { + use EventNameTrait { + getNameForTransition as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Event/EnterEvent.php b/src/Symfony/Component/Workflow/Event/EnterEvent.php index 46213d48ff46..46e104135211 100644 --- a/src/Symfony/Component/Workflow/Event/EnterEvent.php +++ b/src/Symfony/Component/Workflow/Event/EnterEvent.php @@ -17,6 +17,9 @@ final class EnterEvent extends Event { + use EventNameTrait { + getNameForPlace as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Event/EnteredEvent.php b/src/Symfony/Component/Workflow/Event/EnteredEvent.php index 17529b8a4d80..a71610d751ad 100644 --- a/src/Symfony/Component/Workflow/Event/EnteredEvent.php +++ b/src/Symfony/Component/Workflow/Event/EnteredEvent.php @@ -17,6 +17,9 @@ final class EnteredEvent extends Event { + use EventNameTrait { + getNameForPlace as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Event/EventNameTrait.php b/src/Symfony/Component/Workflow/Event/EventNameTrait.php new file mode 100644 index 000000000000..97b804c46d09 --- /dev/null +++ b/src/Symfony/Component/Workflow/Event/EventNameTrait.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Event; + +use Symfony\Component\Workflow\Exception\InvalidArgumentException; + +/** + * @author Nicolas Rigaud + * + * @internal + */ +trait EventNameTrait +{ + /** + * Gets the event name for workflow and transition. + * + * @throws InvalidArgumentException If $transitionName is provided without $workflowName + */ + private static function getNameForTransition(?string $workflowName, ?string $transitionName): string + { + return self::computeName($workflowName, $transitionName); + } + + /** + * Gets the event name for workflow and place. + * + * @throws InvalidArgumentException If $placeName is provided without $workflowName + */ + private static function getNameForPlace(?string $workflowName, ?string $placeName): string + { + return self::computeName($workflowName, $placeName); + } + + private static function computeName(?string $workflowName, ?string $transitionOrPlaceName): string + { + $eventName = strtolower(basename(str_replace('\\', '/', static::class), 'Event')); + + if (null === $workflowName) { + if (null !== $transitionOrPlaceName) { + throw new \InvalidArgumentException('Missing workflow name.'); + } + + return sprintf('workflow.%s', $eventName); + } + + if (null === $transitionOrPlaceName) { + return sprintf('workflow.%s.%s', $workflowName, $eventName); + } + + return sprintf('workflow.%s.%s.%s', $workflowName, $eventName, $transitionOrPlaceName); + } +} diff --git a/src/Symfony/Component/Workflow/Event/GuardEvent.php b/src/Symfony/Component/Workflow/Event/GuardEvent.php index 68a57a979b50..fbbcf22d0024 100644 --- a/src/Symfony/Component/Workflow/Event/GuardEvent.php +++ b/src/Symfony/Component/Workflow/Event/GuardEvent.php @@ -23,6 +23,10 @@ */ final class GuardEvent extends Event { + use EventNameTrait { + getNameForTransition as public getName; + } + private TransitionBlockerList $transitionBlockerList; public function __construct(object $subject, Marking $marking, Transition $transition, ?WorkflowInterface $workflow = null) diff --git a/src/Symfony/Component/Workflow/Event/LeaveEvent.php b/src/Symfony/Component/Workflow/Event/LeaveEvent.php index ca7ff1aa1af0..78fd1b6d472b 100644 --- a/src/Symfony/Component/Workflow/Event/LeaveEvent.php +++ b/src/Symfony/Component/Workflow/Event/LeaveEvent.php @@ -17,6 +17,9 @@ final class LeaveEvent extends Event { + use EventNameTrait { + getNameForPlace as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Event/TransitionEvent.php b/src/Symfony/Component/Workflow/Event/TransitionEvent.php index 6bae1595c86f..a7a3dd06be72 100644 --- a/src/Symfony/Component/Workflow/Event/TransitionEvent.php +++ b/src/Symfony/Component/Workflow/Event/TransitionEvent.php @@ -17,6 +17,9 @@ final class TransitionEvent extends Event { + use EventNameTrait { + getNameForTransition as public getName; + } use HasContextTrait; public function __construct(object $subject, Marking $marking, ?Transition $transition = null, ?WorkflowInterface $workflow = null, array $context = []) diff --git a/src/Symfony/Component/Workflow/Tests/Event/EventNameTraitTest.php b/src/Symfony/Component/Workflow/Tests/Event/EventNameTraitTest.php new file mode 100644 index 000000000000..3c745234a730 --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/Event/EventNameTraitTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Tests\Event; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Workflow\Event\AnnounceEvent; +use Symfony\Component\Workflow\Event\CompletedEvent; +use Symfony\Component\Workflow\Event\EnteredEvent; +use Symfony\Component\Workflow\Event\EnterEvent; +use Symfony\Component\Workflow\Event\GuardEvent; +use Symfony\Component\Workflow\Event\LeaveEvent; +use Symfony\Component\Workflow\Event\TransitionEvent; + +class EventNameTraitTest extends TestCase +{ + /** + * @dataProvider getEvents + * + * @param class-string $class + */ + public function testEventNames(string $class, ?string $workflowName, ?string $transitionOrPlaceName, string $expected) + { + $name = $class::getName($workflowName, $transitionOrPlaceName); + $this->assertEquals($expected, $name); + } + + public static function getEvents(): iterable + { + yield [AnnounceEvent::class, null, null, 'workflow.announce']; + yield [AnnounceEvent::class, 'post', null, 'workflow.post.announce']; + yield [AnnounceEvent::class, 'post', 'publish', 'workflow.post.announce.publish']; + + yield [CompletedEvent::class, null, null, 'workflow.completed']; + yield [CompletedEvent::class, 'post', null, 'workflow.post.completed']; + yield [CompletedEvent::class, 'post', 'publish', 'workflow.post.completed.publish']; + + yield [EnteredEvent::class, null, null, 'workflow.entered']; + yield [EnteredEvent::class, 'post', null, 'workflow.post.entered']; + yield [EnteredEvent::class, 'post', 'published', 'workflow.post.entered.published']; + + yield [EnterEvent::class, null, null, 'workflow.enter']; + yield [EnterEvent::class, 'post', null, 'workflow.post.enter']; + yield [EnterEvent::class, 'post', 'published', 'workflow.post.enter.published']; + + yield [GuardEvent::class, null, null, 'workflow.guard']; + yield [GuardEvent::class, 'post', null, 'workflow.post.guard']; + yield [GuardEvent::class, 'post', 'publish', 'workflow.post.guard.publish']; + + yield [LeaveEvent::class, null, null, 'workflow.leave']; + yield [LeaveEvent::class, 'post', null, 'workflow.post.leave']; + yield [LeaveEvent::class, 'post', 'published', 'workflow.post.leave.published']; + + yield [TransitionEvent::class, null, null, 'workflow.transition']; + yield [TransitionEvent::class, 'post', null, 'workflow.post.transition']; + yield [TransitionEvent::class, 'post', 'publish', 'workflow.post.transition.publish']; + } + + public function testInvalidArgumentExceptionIsThrownIfWorkflowNameIsMissing() + { + $this->expectException(\InvalidArgumentException::class); + + EnterEvent::getName(null, 'place'); + } +}