From 74fffece2459b9cf4c542f76010a152a34421bbf Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 10 Dec 2024 09:51:17 +0100 Subject: [PATCH 01/11] [Workflow] Update union to intersection for mock type --- Tests/Debug/TraceableWorkflowTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Debug/TraceableWorkflowTest.php b/Tests/Debug/TraceableWorkflowTest.php index 3d8e699..257ad66 100644 --- a/Tests/Debug/TraceableWorkflowTest.php +++ b/Tests/Debug/TraceableWorkflowTest.php @@ -21,7 +21,7 @@ class TraceableWorkflowTest extends TestCase { - private MockObject|Workflow $innerWorkflow; + private MockObject&Workflow $innerWorkflow; private Stopwatch $stopwatch; From e63b1886ab3fb3a0bf7acb2a8d614eb48d706b5e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 2 Mar 2025 16:03:52 +0100 Subject: [PATCH 02/11] replace assertEmpty() with stricter assertions --- Tests/WorkflowTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/WorkflowTest.php b/Tests/WorkflowTest.php index e78530a..18cbaf0 100644 --- a/Tests/WorkflowTest.php +++ b/Tests/WorkflowTest.php @@ -734,7 +734,7 @@ public function testGetEnabledTransitions() }); $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher, 'workflow_name'); - $this->assertEmpty($workflow->getEnabledTransitions($subject)); + $this->assertSame([], $workflow->getEnabledTransitions($subject)); $subject->setMarking(['d' => 1]); $transitions = $workflow->getEnabledTransitions($subject); From 82d0fa52166a953b09ee5f20275078cd6a44acc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 10 Apr 2025 14:54:55 +0200 Subject: [PATCH 03/11] [Workflow] Fix dispatch of entered event when the subject is already in this marking --- Tests/WorkflowTest.php | 39 +++++++++++++++++++++++++++++++++++++++ Workflow.php | 8 +++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Tests/WorkflowTest.php b/Tests/WorkflowTest.php index 8e112df..543398a 100644 --- a/Tests/WorkflowTest.php +++ b/Tests/WorkflowTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\Event\EnteredEvent; use Symfony\Component\Workflow\Event\Event; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Event\TransitionEvent; @@ -685,6 +686,44 @@ public function testEventDefaultInitialContext() $workflow->apply($subject, 't1'); } + public function testEventWhenAlreadyInThisPlace() + { + // ┌──────┐ ┌──────────────────────┐ ┌───┐ ┌─────────────┐ ┌───┐ + // │ init │ ──▶ │ from_init_to_a_and_b │ ──▶ │ B │ ──▶ │ from_b_to_c │ ──▶ │ C │ + // └──────┘ └──────────────────────┘ └───┘ └─────────────┘ └───┘ + // │ + // │ + // ▼ + // ┌───────────────────────────────┐ + // │ A │ + // └───────────────────────────────┘ + $definition = new Definition( + ['init', 'A', 'B', 'C'], + [ + new Transition('from_init_to_a_and_b', 'init', ['A', 'B']), + new Transition('from_b_to_c', 'B', 'C'), + ], + ); + + $subject = new Subject(); + $dispatcher = new EventDispatcher(); + $name = 'workflow_name'; + $workflow = new Workflow($definition, new MethodMarkingStore(), $dispatcher, $name); + + $calls = []; + $listener = function (Event $event) use (&$calls) { + $calls[] = $event; + }; + $dispatcher->addListener("workflow.$name.entered.A", $listener); + + $workflow->apply($subject, 'from_init_to_a_and_b'); + $workflow->apply($subject, 'from_b_to_c'); + + $this->assertCount(1, $calls); + $this->assertInstanceOf(EnteredEvent::class, $calls[0]); + $this->assertSame('from_init_to_a_and_b', $calls[0]->getTransition()->getName()); + } + public function testMarkingStateOnApplyWithEventDispatcher() { $definition = new Definition(range('a', 'f'), [new Transition('t', range('a', 'c'), range('d', 'f'))]); diff --git a/Workflow.php b/Workflow.php index 1bad55e..818fbc2 100644 --- a/Workflow.php +++ b/Workflow.php @@ -391,7 +391,13 @@ private function entered(object $subject, ?Transition $transition, Marking $mark $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); - foreach ($marking->getPlaces() as $placeName => $nbToken) { + $placeNames = []; + if ($transition) { + $placeNames = $transition->getTos(); + } elseif ($this->definition->getInitialPlaces()) { + $placeNames = $this->definition->getInitialPlaces(); + } + foreach ($placeNames as $placeName) { $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); } } From 3990b36584b15b9e532375e49fd2d49abf6f17fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 10 Apr 2025 14:00:01 +0200 Subject: [PATCH 04/11] [Workflow] Add a link to mermaid.live from the profiler --- DataCollector/WorkflowDataCollector.php | 35 +++++++++++++++++-------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/DataCollector/WorkflowDataCollector.php b/DataCollector/WorkflowDataCollector.php index febc975..0cb7e20 100644 --- a/DataCollector/WorkflowDataCollector.php +++ b/DataCollector/WorkflowDataCollector.php @@ -88,21 +88,39 @@ public function getCallsCount(): int return $i; } + public function hash(string $string): string + { + return hash('xxh128', $string); + } + + public function buildMermaidLiveLink(string $name): string + { + $payload = [ + 'code' => $this->data['workflows'][$name]['dump'], + 'mermaid' => '{"theme": "default"}', + 'autoSync' => false, + ]; + + $compressed = zlib_encode(json_encode($payload), ZLIB_ENCODING_DEFLATE); + + $suffix = rtrim(strtr(base64_encode($compressed), '+/', '-_'), '='); + + return "https://mermaid.live/edit#pako:{$suffix}"; + } + protected function getCasters(): array { return [ ...parent::getCasters(), - TransitionBlocker::class => function ($v, array $a, Stub $s, $isNested) { - unset( - $a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'code')], - $a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'parameters')], - ); + TransitionBlocker::class => static function ($v, array $a, Stub $s) { + unset($a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'code')]); + unset($a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'parameters')]); $s->cut += 2; return $a; }, - Marking::class => function ($v, array $a, Stub $s, $isNested) { + Marking::class => static function ($v, array $a) { $a[Caster::PREFIX_VIRTUAL.'.places'] = array_keys($v->getPlaces()); return $a; @@ -110,11 +128,6 @@ protected function getCasters(): array ]; } - public function hash(string $string): string - { - return hash('xxh128', $string); - } - private function getEventListeners(WorkflowInterface $workflow): array { $listeners = []; From 492ec937d2f30f9fdd08e202e13196406a0f3eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Fri, 11 Apr 2025 15:52:48 +0200 Subject: [PATCH 05/11] [Workflow] Add more tests --- Tests/Validator/WorkflowValidatorTest.php | 34 +++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/Tests/Validator/WorkflowValidatorTest.php b/Tests/Validator/WorkflowValidatorTest.php index 036ece7..49f0400 100644 --- a/Tests/Validator/WorkflowValidatorTest.php +++ b/Tests/Validator/WorkflowValidatorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Workflow\Tests\Validator; use PHPUnit\Framework\TestCase; +use Symfony\Component\Workflow\Arc; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Exception\InvalidDefinitionException; use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait; @@ -24,8 +25,6 @@ class WorkflowValidatorTest extends TestCase public function testWorkflowWithInvalidNames() { - $this->expectException(InvalidDefinitionException::class); - $this->expectExceptionMessage('All transitions for a place must have an unique name. Multiple transitions named "t1" where found for place "a" in workflow "foo".'); $places = range('a', 'c'); $transitions = []; @@ -35,6 +34,9 @@ public function testWorkflowWithInvalidNames() $definition = new Definition($places, $transitions); + $this->expectException(InvalidDefinitionException::class); + $this->expectExceptionMessage('All transitions for a place must have an unique name. Multiple transitions named "t1" where found for place "a" in workflow "foo".'); + (new WorkflowValidator())->validate($definition, 'foo'); } @@ -54,4 +56,32 @@ public function testSameTransitionNameButNotSamePlace() // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) $this->addToAssertionCount(1); } + + public function testWithTooManyOutput() + { + $places = ['a', 'b', 'c']; + $transitions = [ + new Transition('t1', 'a', ['b', 'c']), + ]; + $definition = new Definition($places, $transitions); + + $this->expectException(InvalidDefinitionException::class); + $this->expectExceptionMessage('The marking store of workflow "foo" cannot store many places. But the transition "t1" has too many output (2). Only one is accepted.'); + + (new WorkflowValidator(true))->validate($definition, 'foo'); + } + + public function testWithTooManyInitialPlaces() + { + $places = ['a', 'b', 'c']; + $transitions = [ + new Transition('t1', 'a', 'b'), + ]; + $definition = new Definition($places, $transitions, ['a', 'b']); + + $this->expectException(InvalidDefinitionException::class); + $this->expectExceptionMessage('The marking store of workflow "foo" cannot store many places. But the definition has 2 initial places. Only one is supported.'); + + (new WorkflowValidator(true))->validate($definition, 'foo'); + } } From c1ffe3d69e1e7e1f9eee4300e1c55911fbbec5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 10 Apr 2025 16:21:22 +0200 Subject: [PATCH 06/11] [Workflow] Deprecate `Event::getWorkflow()` method --- CHANGELOG.md | 7 ++++++- Event/Event.php | 5 +++++ composer.json | 7 ++++--- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2926da4..5a37ead 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ CHANGELOG ========= +7.3 +--- + + * Deprecate `Event::getWorkflow()` method + 7.1 --- * 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 + * Add method `getName()` in event classes to build event names in subscribers 7.0 --- diff --git a/Event/Event.php b/Event/Event.php index c3e6a6f..c13818b 100644 --- a/Event/Event.php +++ b/Event/Event.php @@ -46,8 +46,13 @@ public function getTransition(): ?Transition return $this->transition; } + /** + * @deprecated since Symfony 7.3, inject the workflow in the constructor where you need it + */ public function getWorkflow(): WorkflowInterface { + trigger_deprecation('symfony/workflow', '7.3', 'The "%s()" method is deprecated, inject the workflow in the constructor where you need it.', __METHOD__); + return $this->workflow; } diff --git a/composer.json b/composer.json index 44a3000..ef6779c 100644 --- a/composer.json +++ b/composer.json @@ -20,15 +20,16 @@ } ], "require": { - "php": ">=8.2" + "php": ">=8.2", + "symfony/deprecation-contracts": "2.5|^3" }, "require-dev": { "psr/log": "^1|^2|^3", "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", "symfony/error-handler": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", "symfony/security-core": "^6.4|^7.0", "symfony/stopwatch": "^6.4|^7.0", "symfony/validator": "^6.4|^7.0" From cd0203f9b3ad04a4254385475ff2784811a49998 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 18 Apr 2025 14:51:48 +0200 Subject: [PATCH 07/11] Don't enable tracing unless the profiler is enabled --- Debug/TraceableWorkflow.php | 4 ++++ DependencyInjection/WorkflowDebugPass.php | 1 + 2 files changed, 5 insertions(+) diff --git a/Debug/TraceableWorkflow.php b/Debug/TraceableWorkflow.php index 6d0afd8..c783e63 100644 --- a/Debug/TraceableWorkflow.php +++ b/Debug/TraceableWorkflow.php @@ -30,6 +30,7 @@ class TraceableWorkflow implements WorkflowInterface public function __construct( private readonly WorkflowInterface $workflow, private readonly Stopwatch $stopwatch, + protected readonly ?\Closure $disabled = null, ) { } @@ -90,6 +91,9 @@ public function getCalls(): array private function callInner(string $method, array $args): mixed { + if ($this->disabled?->__invoke()) { + return $this->workflow->{$method}(...$args); + } $sMethod = $this->workflow::class.'::'.$method; $this->stopwatch->start($sMethod, 'workflow'); diff --git a/DependencyInjection/WorkflowDebugPass.php b/DependencyInjection/WorkflowDebugPass.php index 634605d..042aaba 100644 --- a/DependencyInjection/WorkflowDebugPass.php +++ b/DependencyInjection/WorkflowDebugPass.php @@ -31,6 +31,7 @@ public function process(ContainerBuilder $container): void ->setArguments([ new Reference("debug.{$id}.inner"), new Reference('debug.stopwatch'), + new Reference('profiler.is_disabled_state_checker', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), ]); } } From f8490656e99ae9558054a9586a77cfce271b7f7e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Apr 2025 15:26:02 +0200 Subject: [PATCH 08/11] Remove unneeded use statements --- Tests/Validator/WorkflowValidatorTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/Validator/WorkflowValidatorTest.php b/Tests/Validator/WorkflowValidatorTest.php index 49f0400..50c3abd 100644 --- a/Tests/Validator/WorkflowValidatorTest.php +++ b/Tests/Validator/WorkflowValidatorTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Workflow\Tests\Validator; use PHPUnit\Framework\TestCase; -use Symfony\Component\Workflow\Arc; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Exception\InvalidDefinitionException; use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait; From 238b84b3e5de703a5c62fd26cb1f2bbe0e3057b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 13 Mar 2024 18:34:52 +0100 Subject: [PATCH 09/11] [Workflow] Add support for executing custom workflow definition validators during the container compilation --- DependencyInjection/WorkflowValidatorPass.php | 37 ++++++++++ .../WorkflowValidatorPassTest.php | 74 +++++++++++++++++++ composer.json | 1 + 3 files changed, 112 insertions(+) create mode 100644 DependencyInjection/WorkflowValidatorPass.php create mode 100644 Tests/DependencyInjection/WorkflowValidatorPassTest.php diff --git a/DependencyInjection/WorkflowValidatorPass.php b/DependencyInjection/WorkflowValidatorPass.php new file mode 100644 index 0000000..60072ef --- /dev/null +++ b/DependencyInjection/WorkflowValidatorPass.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\DependencyInjection; + +use Symfony\Component\Config\Resource\FileResource; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\LogicException; + +/** + * @author Grégoire Pineau + */ +class WorkflowValidatorPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container): void + { + foreach ($container->findTaggedServiceIds('workflow') as $attributes) { + foreach ($attributes as $attribute) { + foreach ($attribute['definition_validators'] ?? [] as $validatorClass) { + $container->addResource(new FileResource($container->getReflectionClass($validatorClass)->getFileName())); + + $realDefinition = $container->get($attribute['definition_id'] ?? throw new \LogicException('The "definition_id" attribute is required.')); + (new $validatorClass())->validate($realDefinition, $attribute['name'] ?? throw new \LogicException('The "name" attribute is required.')); + } + } + } + } +} diff --git a/Tests/DependencyInjection/WorkflowValidatorPassTest.php b/Tests/DependencyInjection/WorkflowValidatorPassTest.php new file mode 100644 index 0000000..213e0d4 --- /dev/null +++ b/Tests/DependencyInjection/WorkflowValidatorPassTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass; +use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface; +use Symfony\Component\Workflow\WorkflowInterface; + +class WorkflowValidatorPassTest extends TestCase +{ + private ContainerBuilder $container; + private WorkflowValidatorPass $compilerPass; + + protected function setUp(): void + { + $this->container = new ContainerBuilder(); + $this->compilerPass = new WorkflowValidatorPass(); + } + + public function testNothingToDo() + { + $this->compilerPass->process($this->container); + + $this->assertFalse(DefinitionValidator::$called); + } + + public function testValidate() + { + $this + ->container + ->register('my.workflow', WorkflowInterface::class) + ->addTag('workflow', [ + 'definition_id' => 'my.workflow.definition', + 'name' => 'my.workflow', + 'definition_validators' => [DefinitionValidator::class], + ]) + ; + + $this + ->container + ->register('my.workflow.definition', Definition::class) + ->setArguments([ + '$places' => [], + '$transitions' => [], + ]) + ; + + $this->compilerPass->process($this->container); + + $this->assertTrue(DefinitionValidator::$called); + } +} + +class DefinitionValidator implements DefinitionValidatorInterface +{ + public static bool $called = false; + + public function validate(Definition $definition, string $name): void + { + self::$called = true; + } +} diff --git a/composer.json b/composer.json index ef6779c..3e2c50a 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ }, "require-dev": { "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", "symfony/dependency-injection": "^6.4|^7.0", "symfony/error-handler": "^6.4|^7.0", "symfony/event-dispatcher": "^6.4|^7.0", From ffcbdf0c33e4534912d1174bbfd0549dd3bb10f3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 10 Jul 2025 09:12:18 +0200 Subject: [PATCH 10/11] CS fixes --- Attribute/BuildEventNameTrait.php | 8 ++--- DataCollector/WorkflowDataCollector.php | 16 +++++----- Definition.php | 6 ++-- .../WorkflowGuardListenerPass.php | 2 +- Dumper/GraphvizDumper.php | 32 +++++++++---------- Dumper/MermaidDumper.php | 22 ++++++------- Dumper/PlantUmlDumper.php | 6 ++-- Dumper/StateMachineGraphvizDumper.php | 2 +- EventListener/AuditTrailListener.php | 6 ++-- EventListener/ExpressionLanguage.php | 4 +-- Exception/NotEnabledTransitionException.php | 2 +- Exception/UndefinedTransitionException.php | 2 +- MarkingStore/MethodMarkingStore.php | 6 ++-- Registry.php | 4 +-- Tests/Attribute/AsListenerTest.php | 4 +-- Tests/Debug/TraceableWorkflowTest.php | 2 +- Tests/Dumper/MermaidDumperTest.php | 12 +++---- Tests/StateMachineTest.php | 4 +-- Validator/StateMachineValidator.php | 8 ++--- Validator/WorkflowValidator.php | 6 ++-- Workflow.php | 32 +++++++++---------- 21 files changed, 93 insertions(+), 93 deletions(-) diff --git a/Attribute/BuildEventNameTrait.php b/Attribute/BuildEventNameTrait.php index 93eeee7..d6d3c26 100644 --- a/Attribute/BuildEventNameTrait.php +++ b/Attribute/BuildEventNameTrait.php @@ -24,16 +24,16 @@ private static function buildEventName(string $keyword, string $argument, ?strin { if (null === $workflow) { if (null !== $node) { - throw new LogicException(sprintf('The "%s" argument of "%s" cannot be used without a "workflow" argument.', $argument, self::class)); + throw new LogicException(\sprintf('The "%s" argument of "%s" cannot be used without a "workflow" argument.', $argument, self::class)); } - return sprintf('workflow.%s', $keyword); + return \sprintf('workflow.%s', $keyword); } if (null === $node) { - return sprintf('workflow.%s.%s', $workflow, $keyword); + return \sprintf('workflow.%s.%s', $workflow, $keyword); } - return sprintf('workflow.%s.%s.%s', $workflow, $keyword, $node); + return \sprintf('workflow.%s.%s.%s', $workflow, $keyword, $node); } } diff --git a/DataCollector/WorkflowDataCollector.php b/DataCollector/WorkflowDataCollector.php index cf15802..cee5504 100644 --- a/DataCollector/WorkflowDataCollector.php +++ b/DataCollector/WorkflowDataCollector.php @@ -94,8 +94,8 @@ protected function getCasters(): array ...parent::getCasters(), TransitionBlocker::class => function ($v, array $a, Stub $s, $isNested) { unset( - $a[sprintf(Caster::PATTERN_PRIVATE, $v::class, 'code')], - $a[sprintf(Caster::PATTERN_PRIVATE, $v::class, 'parameters')], + $a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'code')], + $a[\sprintf(Caster::PATTERN_PRIVATE, $v::class, 'parameters')], ); $s->cut += 2; @@ -129,9 +129,9 @@ private function getEventListeners(WorkflowInterface $workflow): array 'entered', ]; foreach ($subEventNames as $subEventName) { - $eventNames[] = sprintf('workflow.%s', $subEventName); - $eventNames[] = sprintf('workflow.%s.%s', $workflow->getName(), $subEventName); - $eventNames[] = sprintf('workflow.%s.%s.%s', $workflow->getName(), $subEventName, $place); + $eventNames[] = \sprintf('workflow.%s', $subEventName); + $eventNames[] = \sprintf('workflow.%s.%s', $workflow->getName(), $subEventName); + $eventNames[] = \sprintf('workflow.%s.%s.%s', $workflow->getName(), $subEventName, $place); } foreach ($eventNames as $eventName) { foreach ($this->eventDispatcher->getListeners($eventName) as $listener) { @@ -151,9 +151,9 @@ private function getEventListeners(WorkflowInterface $workflow): array 'announce', ]; foreach ($subEventNames as $subEventName) { - $eventNames[] = sprintf('workflow.%s', $subEventName); - $eventNames[] = sprintf('workflow.%s.%s', $workflow->getName(), $subEventName); - $eventNames[] = sprintf('workflow.%s.%s.%s', $workflow->getName(), $subEventName, $transition->getName()); + $eventNames[] = \sprintf('workflow.%s', $subEventName); + $eventNames[] = \sprintf('workflow.%s.%s', $workflow->getName(), $subEventName); + $eventNames[] = \sprintf('workflow.%s.%s.%s', $workflow->getName(), $subEventName, $transition->getName()); } foreach ($eventNames as $eventName) { foreach ($this->eventDispatcher->getListeners($eventName) as $listener) { diff --git a/Definition.php b/Definition.php index e876b9f..bf8e888 100644 --- a/Definition.php +++ b/Definition.php @@ -89,7 +89,7 @@ private function setInitialPlaces(string|array|null $places = null): void foreach ($places as $place) { if (!isset($this->places[$place])) { - throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); + throw new LogicException(\sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); } } @@ -111,13 +111,13 @@ private function addTransition(Transition $transition): void foreach ($transition->getFroms() as $from) { if (!isset($this->places[$from])) { - throw new LogicException(sprintf('Place "%s" referenced in transition "%s" does not exist.', $from, $name)); + throw new LogicException(\sprintf('Place "%s" referenced in transition "%s" does not exist.', $from, $name)); } } foreach ($transition->getTos() as $to) { if (!isset($this->places[$to])) { - throw new LogicException(sprintf('Place "%s" referenced in transition "%s" does not exist.', $to, $name)); + throw new LogicException(\sprintf('Place "%s" referenced in transition "%s" does not exist.', $to, $name)); } } diff --git a/DependencyInjection/WorkflowGuardListenerPass.php b/DependencyInjection/WorkflowGuardListenerPass.php index ba81a7b..ccf00f0 100644 --- a/DependencyInjection/WorkflowGuardListenerPass.php +++ b/DependencyInjection/WorkflowGuardListenerPass.php @@ -38,7 +38,7 @@ public function process(ContainerBuilder $container): void foreach ($servicesNeeded as $service) { if (!$container->has($service)) { - throw new LogicException(sprintf('The "%s" service is needed to be able to use the workflow guard listener.', $service)); + throw new LogicException(\sprintf('The "%s" service is needed to be able to use the workflow guard listener.', $service)); } } } diff --git a/Dumper/GraphvizDumper.php b/Dumper/GraphvizDumper.php index 9a99690..36a5be9 100644 --- a/Dumper/GraphvizDumper.php +++ b/Dumper/GraphvizDumper.php @@ -154,14 +154,14 @@ protected function addPlaces(array $places, float $withMetadata): string } if ($withMetadata) { - $escapedLabel = sprintf('<%s%s>', $this->escape($placeName), $this->addMetadata($place['attributes']['metadata'])); + $escapedLabel = \sprintf('<%s%s>', $this->escape($placeName), $this->addMetadata($place['attributes']['metadata'])); // Don't include metadata in default attributes used to format the place unset($place['attributes']['metadata']); } else { - $escapedLabel = sprintf('"%s"', $this->escape($placeName)); + $escapedLabel = \sprintf('"%s"', $this->escape($placeName)); } - $code .= sprintf(" place_%s [label=%s, shape=circle%s];\n", $this->dotize($id), $escapedLabel, $this->addAttributes($place['attributes'])); + $code .= \sprintf(" place_%s [label=%s, shape=circle%s];\n", $this->dotize($id), $escapedLabel, $this->addAttributes($place['attributes'])); } return $code; @@ -176,12 +176,12 @@ protected function addTransitions(array $transitions, bool $withMetadata): strin foreach ($transitions as $i => $place) { if ($withMetadata) { - $escapedLabel = sprintf('<%s%s>', $this->escape($place['name']), $this->addMetadata($place['metadata'])); + $escapedLabel = \sprintf('<%s%s>', $this->escape($place['name']), $this->addMetadata($place['metadata'])); } else { $escapedLabel = '"'.$this->escape($place['name']).'"'; } - $code .= sprintf(" transition_%s [label=%s,%s];\n", $this->dotize($i), $escapedLabel, $this->addAttributes($place['attributes'])); + $code .= \sprintf(" transition_%s [label=%s,%s];\n", $this->dotize($i), $escapedLabel, $this->addAttributes($place['attributes'])); } return $code; @@ -229,12 +229,12 @@ protected function addEdges(array $edges): string foreach ($edges as $edge) { if ('from' === $edge['direction']) { - $code .= sprintf(" place_%s -> transition_%s [style=\"solid\"];\n", + $code .= \sprintf(" place_%s -> transition_%s [style=\"solid\"];\n", $this->dotize($edge['from']), $this->dotize($edge['transition_number']) ); } else { - $code .= sprintf(" transition_%s -> place_%s [style=\"solid\"];\n", + $code .= \sprintf(" transition_%s -> place_%s [style=\"solid\"];\n", $this->dotize($edge['transition_number']), $this->dotize($edge['to']) ); @@ -249,9 +249,9 @@ protected function addEdges(array $edges): string */ protected function startDot(array $options, string $label): string { - return sprintf("digraph workflow {\n %s%s\n node [%s];\n edge [%s];\n\n", + return \sprintf("digraph workflow {\n %s%s\n node [%s];\n edge [%s];\n\n", $this->addOptions($options['graph']), - '""' !== $label && '<>' !== $label ? sprintf(' label=%s', $label) : '', + '""' !== $label && '<>' !== $label ? \sprintf(' label=%s', $label) : '', $this->addOptions($options['node']), $this->addOptions($options['edge']) ); @@ -289,7 +289,7 @@ protected function addAttributes(array $attributes): string $code = []; foreach ($attributes as $k => $v) { - $code[] = sprintf('%s="%s"', $k, $this->escape($v)); + $code[] = \sprintf('%s="%s"', $k, $this->escape($v)); } return $code ? ' '.implode(' ', $code) : ''; @@ -309,17 +309,17 @@ protected function formatLabel(Definition $definition, string $withMetadata, arr if (!$withMetadata) { // Only currentLabel to handle. If null, will be translated to empty string - return sprintf('"%s"', $this->escape($currentLabel)); + return \sprintf('"%s"', $this->escape($currentLabel)); } $workflowMetadata = $definition->getMetadataStore()->getWorkflowMetadata(); if ('' === $currentLabel) { // Only metadata to handle - return sprintf('<%s>', $this->addMetadata($workflowMetadata, false)); + return \sprintf('<%s>', $this->addMetadata($workflowMetadata, false)); } // currentLabel and metadata to handle - return sprintf('<%s%s>', $this->escape($currentLabel), $this->addMetadata($workflowMetadata)); + return \sprintf('<%s%s>', $this->escape($currentLabel), $this->addMetadata($workflowMetadata)); } private function addOptions(array $options): string @@ -327,7 +327,7 @@ private function addOptions(array $options): string $code = []; foreach ($options as $k => $v) { - $code[] = sprintf('%s="%s"', $k, $v); + $code[] = \sprintf('%s="%s"', $k, $v); } return implode(' ', $code); @@ -344,10 +344,10 @@ private function addMetadata(array $metadata, bool $lineBreakFirstIfNotEmpty = t foreach ($metadata as $key => $value) { if ($skipSeparator) { - $code[] = sprintf('%s: %s', $this->escape($key), $this->escape($value)); + $code[] = \sprintf('%s: %s', $this->escape($key), $this->escape($value)); $skipSeparator = false; } else { - $code[] = sprintf('%s%s: %s', '
', $this->escape($key), $this->escape($value)); + $code[] = \sprintf('%s%s: %s', '
', $this->escape($key), $this->escape($value)); } } diff --git a/Dumper/MermaidDumper.php b/Dumper/MermaidDumper.php index d2f2d6e..69220ee 100644 --- a/Dumper/MermaidDumper.php +++ b/Dumper/MermaidDumper.php @@ -142,7 +142,7 @@ private function preparePlace(int $placeId, string $placeName, array $meta, bool $placeNodeName = 'place'.$placeId; $placeNodeFormat = '%s'.$labelShape; - $placeNode = sprintf($placeNodeFormat, $placeNodeName, $placeLabel); + $placeNode = \sprintf($placeNodeFormat, $placeNodeName, $placeLabel); $placeStyle = $this->styleNode($meta, $placeNodeName, $hasMarking); @@ -154,7 +154,7 @@ private function styleNode(array $meta, string $nodeName, bool $hasMarking = fal $nodeStyles = []; if (\array_key_exists('bg_color', $meta)) { - $nodeStyles[] = sprintf( + $nodeStyles[] = \sprintf( 'fill:%s', $meta['bg_color'] ); @@ -168,7 +168,7 @@ private function styleNode(array $meta, string $nodeName, bool $hasMarking = fal return ''; } - return sprintf('style %s %s', $nodeName, implode(',', $nodeStyles)); + return \sprintf('style %s %s', $nodeName, implode(',', $nodeStyles)); } /** @@ -179,26 +179,26 @@ private function escape(string $label): string { $label = str_replace('"', '#quot;', $label); - return sprintf('"%s"', $label); + return \sprintf('"%s"', $label); } public function validateDirection(string $direction): void { if (!\in_array($direction, self::VALID_DIRECTIONS, true)) { - throw new InvalidArgumentException(sprintf('Direction "%s" is not valid, valid directions are: "%s".', $direction, implode(', ', self::VALID_DIRECTIONS))); + throw new InvalidArgumentException(\sprintf('Direction "%s" is not valid, valid directions are: "%s".', $direction, implode(', ', self::VALID_DIRECTIONS))); } } private function validateTransitionType(string $transitionType): void { if (!\in_array($transitionType, self::VALID_TRANSITION_TYPES, true)) { - throw new InvalidArgumentException(sprintf('Transition type "%s" is not valid, valid types are: "%s".', $transitionType, implode(', ', self::VALID_TRANSITION_TYPES))); + throw new InvalidArgumentException(\sprintf('Transition type "%s" is not valid, valid types are: "%s".', $transitionType, implode(', ', self::VALID_TRANSITION_TYPES))); } } private function styleStateMachineTransition(string $from, string $to, string $transitionLabel, array $transitionMeta): array { - $transitionOutput = [sprintf('%s-->|%s|%s', $from, str_replace("\n", ' ', $this->escape($transitionLabel)), $to)]; + $transitionOutput = [\sprintf('%s-->|%s|%s', $from, str_replace("\n", ' ', $this->escape($transitionLabel)), $to)]; $linkStyle = $this->styleLink($transitionMeta); if ('' !== $linkStyle) { @@ -217,7 +217,7 @@ private function styleWorkflowTransition(string $from, string $to, int $transiti $transitionLabel = $this->escape($transitionLabel); $transitionNodeName = 'transition'.$transitionId; - $transitionOutput[] = sprintf('%s[%s]', $transitionNodeName, $transitionLabel); + $transitionOutput[] = \sprintf('%s[%s]', $transitionNodeName, $transitionLabel); $transitionNodeStyle = $this->styleNode($transitionMeta, $transitionNodeName); if ('' !== $transitionNodeStyle) { @@ -225,7 +225,7 @@ private function styleWorkflowTransition(string $from, string $to, int $transiti } $connectionStyle = '%s-->%s'; - $transitionOutput[] = sprintf($connectionStyle, $from, $transitionNodeName); + $transitionOutput[] = \sprintf($connectionStyle, $from, $transitionNodeName); $linkStyle = $this->styleLink($transitionMeta); if ('' !== $linkStyle) { @@ -234,7 +234,7 @@ private function styleWorkflowTransition(string $from, string $to, int $transiti ++$this->linkCount; - $transitionOutput[] = sprintf($connectionStyle, $transitionNodeName, $to); + $transitionOutput[] = \sprintf($connectionStyle, $transitionNodeName, $to); $linkStyle = $this->styleLink($transitionMeta); if ('' !== $linkStyle) { @@ -249,7 +249,7 @@ private function styleWorkflowTransition(string $from, string $to, int $transiti private function styleLink(array $transitionMeta): string { if (\array_key_exists('color', $transitionMeta)) { - return sprintf('linkStyle %d stroke:%s', $this->linkCount, $transitionMeta['color']); + return \sprintf('linkStyle %d stroke:%s', $this->linkCount, $transitionMeta['color']); } return ''; diff --git a/Dumper/PlantUmlDumper.php b/Dumper/PlantUmlDumper.php index 2a232d4..e2f5859 100644 --- a/Dumper/PlantUmlDumper.php +++ b/Dumper/PlantUmlDumper.php @@ -228,9 +228,9 @@ private function getTransitionEscapedWithStyle(MetadataStoreInterface $workflowM if (null !== $color) { // Close and open before and after every '\n' string, // so that the style is applied properly on every line - $to = str_replace('\n', sprintf('\n', $color), $to); + $to = str_replace('\n', \sprintf('\n', $color), $to); - $to = sprintf( + $to = \sprintf( '%2$s', $color, $to @@ -247,7 +247,7 @@ private function getTransitionColor(string $color): string $color = '#'.$color; } - return sprintf('[%s]', $color); + return \sprintf('[%s]', $color); } private function getColorId(string $color): string diff --git a/Dumper/StateMachineGraphvizDumper.php b/Dumper/StateMachineGraphvizDumper.php index e054cb4..7bd9d73 100644 --- a/Dumper/StateMachineGraphvizDumper.php +++ b/Dumper/StateMachineGraphvizDumper.php @@ -89,7 +89,7 @@ protected function addEdges(array $edges): string foreach ($edges as $id => $edges) { foreach ($edges as $edge) { - $code .= sprintf( + $code .= \sprintf( " place_%s -> place_%s [label=\"%s\" style=\"%s\"%s];\n", $this->dotize($id), $this->dotize($edge['to']), diff --git a/EventListener/AuditTrailListener.php b/EventListener/AuditTrailListener.php index 8d82824..6f50382 100644 --- a/EventListener/AuditTrailListener.php +++ b/EventListener/AuditTrailListener.php @@ -33,7 +33,7 @@ public function __construct(LoggerInterface $logger) public function onLeave(Event $event) { foreach ($event->getTransition()->getFroms() as $place) { - $this->logger->info(sprintf('Leaving "%s" for subject of class "%s" in workflow "%s".', $place, $event->getSubject()::class, $event->getWorkflowName())); + $this->logger->info(\sprintf('Leaving "%s" for subject of class "%s" in workflow "%s".', $place, $event->getSubject()::class, $event->getWorkflowName())); } } @@ -42,7 +42,7 @@ public function onLeave(Event $event) */ public function onTransition(Event $event) { - $this->logger->info(sprintf('Transition "%s" for subject of class "%s" in workflow "%s".', $event->getTransition()->getName(), $event->getSubject()::class, $event->getWorkflowName())); + $this->logger->info(\sprintf('Transition "%s" for subject of class "%s" in workflow "%s".', $event->getTransition()->getName(), $event->getSubject()::class, $event->getWorkflowName())); } /** @@ -51,7 +51,7 @@ public function onTransition(Event $event) public function onEnter(Event $event) { foreach ($event->getTransition()->getTos() as $place) { - $this->logger->info(sprintf('Entering "%s" for subject of class "%s" in workflow "%s".', $place, $event->getSubject()::class, $event->getWorkflowName())); + $this->logger->info(\sprintf('Entering "%s" for subject of class "%s" in workflow "%s".', $place, $event->getSubject()::class, $event->getWorkflowName())); } } diff --git a/EventListener/ExpressionLanguage.php b/EventListener/ExpressionLanguage.php index 82fe165..7848fb3 100644 --- a/EventListener/ExpressionLanguage.php +++ b/EventListener/ExpressionLanguage.php @@ -29,9 +29,9 @@ protected function registerFunctions() { parent::registerFunctions(); - $this->register('is_granted', fn ($attributes, $object = 'null') => sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object), fn (array $variables, $attributes, $object = null) => $variables['auth_checker']->isGranted($attributes, $object)); + $this->register('is_granted', fn ($attributes, $object = 'null') => \sprintf('$auth_checker->isGranted(%s, %s)', $attributes, $object), fn (array $variables, $attributes, $object = null) => $variables['auth_checker']->isGranted($attributes, $object)); - $this->register('is_valid', fn ($object = 'null', $groups = 'null') => sprintf('0 === count($validator->validate(%s, null, %s))', $object, $groups), function (array $variables, $object = null, $groups = null) { + $this->register('is_valid', fn ($object = 'null', $groups = 'null') => \sprintf('0 === count($validator->validate(%s, null, %s))', $object, $groups), function (array $variables, $object = null, $groups = null) { if (!$variables['validator'] instanceof ValidatorInterface) { throw new RuntimeException('"is_valid" cannot be used as the Validator component is not installed. Try running "composer require symfony/validator".'); } diff --git a/Exception/NotEnabledTransitionException.php b/Exception/NotEnabledTransitionException.php index 4144caf..543478c 100644 --- a/Exception/NotEnabledTransitionException.php +++ b/Exception/NotEnabledTransitionException.php @@ -25,7 +25,7 @@ class NotEnabledTransitionException extends TransitionException public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, TransitionBlockerList $transitionBlockerList, array $context = []) { - parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflow->getName()), $context); + parent::__construct($subject, $transitionName, $workflow, \sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflow->getName()), $context); $this->transitionBlockerList = $transitionBlockerList; } diff --git a/Exception/UndefinedTransitionException.php b/Exception/UndefinedTransitionException.php index 75d3848..5a8ecf8 100644 --- a/Exception/UndefinedTransitionException.php +++ b/Exception/UndefinedTransitionException.php @@ -22,6 +22,6 @@ class UndefinedTransitionException extends TransitionException { public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, array $context = []) { - parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflow->getName()), $context); + parent::__construct($subject, $transitionName, $workflow, \sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflow->getName()), $context); } } diff --git a/MarkingStore/MethodMarkingStore.php b/MarkingStore/MethodMarkingStore.php index 773328f..50d6169 100644 --- a/MarkingStore/MethodMarkingStore.php +++ b/MarkingStore/MethodMarkingStore.php @@ -53,7 +53,7 @@ public function getMarking(object $subject): Marking try { $marking = ($this->getGetter($subject))(); } catch (\Error $e) { - $unInitializedPropertyMessage = sprintf('Typed property %s::$%s must not be accessed before initialization', get_debug_type($subject), $this->property); + $unInitializedPropertyMessage = \sprintf('Typed property %s::$%s must not be accessed before initialization', get_debug_type($subject), $this->property); if ($e->getMessage() !== $unInitializedPropertyMessage) { throw $e; } @@ -66,7 +66,7 @@ public function getMarking(object $subject): Marking if ($this->singleState) { $marking = [(string) $marking => 1]; } elseif (!\is_array($marking)) { - throw new LogicException(sprintf('The marking stored in "%s::$%s" is not an array and the Workflow\'s Marking store is instantiated with $singleState=false.', get_debug_type($subject), $this->property)); + throw new LogicException(\sprintf('The marking stored in "%s::$%s" is not an array and the Workflow\'s Marking store is instantiated with $singleState=false.', get_debug_type($subject), $this->property)); } return new Marking($marking); @@ -118,7 +118,7 @@ private static function getType(object $subject, string $property, string $metho } catch (\ReflectionException) { } - throw new LogicException(sprintf('Cannot store marking: class "%s" should have either a public method named "%s()" or a public property named "$%s"; none found.', get_debug_type($subject), $method, $property)); + throw new LogicException(\sprintf('Cannot store marking: class "%s" should have either a public method named "%s()" or a public property named "$%s"; none found.', get_debug_type($subject), $method, $property)); } } diff --git a/Registry.php b/Registry.php index 8041e98..96be3cc 100644 --- a/Registry.php +++ b/Registry.php @@ -52,13 +52,13 @@ public function get(object $subject, ?string $workflowName = null): WorkflowInte } if (!$matched) { - throw new InvalidArgumentException(sprintf('Unable to find a workflow for class "%s".', get_debug_type($subject))); + throw new InvalidArgumentException(\sprintf('Unable to find a workflow for class "%s".', get_debug_type($subject))); } if (2 <= \count($matched)) { $names = array_map(static fn (WorkflowInterface $workflow): string => $workflow->getName(), $matched); - throw new InvalidArgumentException(sprintf('Too many workflows (%s) match this subject (%s); set a different name on each and use the second (name) argument of this method.', implode(', ', $names), get_debug_type($subject))); + throw new InvalidArgumentException(\sprintf('Too many workflows (%s) match this subject (%s); set a different name on each and use the second (name) argument of this method.', implode(', ', $names), get_debug_type($subject))); } return $matched[0]; diff --git a/Tests/Attribute/AsListenerTest.php b/Tests/Attribute/AsListenerTest.php index a858626..0a8c232 100644 --- a/Tests/Attribute/AsListenerTest.php +++ b/Tests/Attribute/AsListenerTest.php @@ -64,7 +64,7 @@ public static function provideOkTests(): iterable public function testTransitionThrowException(string $class) { $this->expectException(LogicException::class); - $this->expectExceptionMessage(sprintf('The "transition" argument of "%s" cannot be used without a "workflow" argument.', $class)); + $this->expectExceptionMessage(\sprintf('The "transition" argument of "%s" cannot be used without a "workflow" argument.', $class)); new $class(transition: 'some'); } @@ -83,7 +83,7 @@ public static function provideTransitionThrowException(): iterable public function testPlaceThrowException(string $class) { $this->expectException(LogicException::class); - $this->expectExceptionMessage(sprintf('The "place" argument of "%s" cannot be used without a "workflow" argument.', $class)); + $this->expectExceptionMessage(\sprintf('The "place" argument of "%s" cannot be used without a "workflow" argument.', $class)); new $class(place: 'some'); } diff --git a/Tests/Debug/TraceableWorkflowTest.php b/Tests/Debug/TraceableWorkflowTest.php index 5bfcee9..3d8e699 100644 --- a/Tests/Debug/TraceableWorkflowTest.php +++ b/Tests/Debug/TraceableWorkflowTest.php @@ -23,7 +23,7 @@ class TraceableWorkflowTest extends TestCase { private MockObject|Workflow $innerWorkflow; - private StopWatch $stopwatch; + private Stopwatch $stopwatch; private TraceableWorkflow $traceableWorkflow; diff --git a/Tests/Dumper/MermaidDumperTest.php b/Tests/Dumper/MermaidDumperTest.php index 3a29da6..a8d1978 100644 --- a/Tests/Dumper/MermaidDumperTest.php +++ b/Tests/Dumper/MermaidDumperTest.php @@ -104,7 +104,7 @@ public static function provideWorkflowDefinitionWithoutMarking(): iterable ."transition4-->place6\n" ."transition5[\"t6\"]\n" ."place5-->transition5\n" - ."transition5-->place6", + .'transition5-->place6', ]; yield [ self::createWorkflowWithSameNameTransition(), @@ -124,7 +124,7 @@ public static function provideWorkflowDefinitionWithoutMarking(): iterable ."transition2-->place0\n" ."transition3[\"to_a\"]\n" ."place2-->transition3\n" - ."transition3-->place0", + .'transition3-->place0', ]; yield [ self::createSimpleWorkflowDefinition(), @@ -140,7 +140,7 @@ public static function provideWorkflowDefinitionWithoutMarking(): iterable ."linkStyle 1 stroke:Grey\n" ."transition1[\"t2\"]\n" ."place1-->transition1\n" - ."transition1-->place2", + .'transition1-->place2', ]; } @@ -169,7 +169,7 @@ public static function provideWorkflowWithReservedWords(): iterable ."place1-->transition0\n" ."transition1[\"t1\"]\n" ."place2-->transition1\n" - ."transition1-->place3", + .'transition1-->place3', ]; } @@ -186,7 +186,7 @@ public static function provideStateMachine(): iterable ."place3-->|\"My custom transition label 3\"|place1\n" ."linkStyle 1 stroke:Grey\n" ."place1-->|\"t2\"|place2\n" - ."place1-->|\"t3\"|place3", + .'place1-->|"t3"|place3', ]; } @@ -212,7 +212,7 @@ public static function provideWorkflowWithMarking(): iterable ."linkStyle 1 stroke:Grey\n" ."transition1[\"t2\"]\n" ."place1-->transition1\n" - ."transition1-->place2", + .'transition1-->place2', ]; } } diff --git a/Tests/StateMachineTest.php b/Tests/StateMachineTest.php index e991707..5d10fde 100644 --- a/Tests/StateMachineTest.php +++ b/Tests/StateMachineTest.php @@ -88,7 +88,7 @@ public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge $net = new StateMachine($definition, null, $dispatcher); $dispatcher->addListener('workflow.guard', function (GuardEvent $event) { - $event->addTransitionBlocker(new TransitionBlocker(sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker')); + $event->addTransitionBlocker(new TransitionBlocker(\sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker')); }); $subject = new Subject(); @@ -124,7 +124,7 @@ public function testApplyReturnsExpectedReasonOnBranchMerge() $net = new StateMachine($definition, null, $dispatcher); $dispatcher->addListener('workflow.guard', function (GuardEvent $event) { - $event->addTransitionBlocker(new TransitionBlocker(sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker')); + $event->addTransitionBlocker(new TransitionBlocker(\sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker')); }); $subject = new Subject(); diff --git a/Validator/StateMachineValidator.php b/Validator/StateMachineValidator.php index 20afc8d..65fd665 100644 --- a/Validator/StateMachineValidator.php +++ b/Validator/StateMachineValidator.php @@ -28,19 +28,19 @@ public function validate(Definition $definition, string $name) foreach ($definition->getTransitions() as $transition) { // Make sure that each transition has exactly one TO if (1 !== \count($transition->getTos())) { - throw new InvalidDefinitionException(sprintf('A transition in StateMachine can only have one output. But the transition "%s" in StateMachine "%s" has %d outputs.', $transition->getName(), $name, \count($transition->getTos()))); + throw new InvalidDefinitionException(\sprintf('A transition in StateMachine can only have one output. But the transition "%s" in StateMachine "%s" has %d outputs.', $transition->getName(), $name, \count($transition->getTos()))); } // Make sure that each transition has exactly one FROM $froms = $transition->getFroms(); if (1 !== \count($froms)) { - throw new InvalidDefinitionException(sprintf('A transition in StateMachine can only have one input. But the transition "%s" in StateMachine "%s" has %d inputs.', $transition->getName(), $name, \count($froms))); + throw new InvalidDefinitionException(\sprintf('A transition in StateMachine can only have one input. But the transition "%s" in StateMachine "%s" has %d inputs.', $transition->getName(), $name, \count($froms))); } // Enforcing uniqueness of the names of transitions starting at each node $from = reset($froms); if (isset($transitionFromNames[$from][$transition->getName()])) { - throw new InvalidDefinitionException(sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" were found on StateMachine "%s".', $transition->getName(), $from, $name)); + throw new InvalidDefinitionException(\sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" were found on StateMachine "%s".', $transition->getName(), $from, $name)); } $transitionFromNames[$from][$transition->getName()] = true; @@ -48,7 +48,7 @@ public function validate(Definition $definition, string $name) $initialPlaces = $definition->getInitialPlaces(); if (2 <= \count($initialPlaces)) { - throw new InvalidDefinitionException(sprintf('The state machine "%s" cannot store many places. But the definition has %d initial places. Only one is supported.', $name, \count($initialPlaces))); + throw new InvalidDefinitionException(\sprintf('The state machine "%s" cannot store many places. But the definition has %d initial places. Only one is supported.', $name, \count($initialPlaces))); } } } diff --git a/Validator/WorkflowValidator.php b/Validator/WorkflowValidator.php index c13c281..e3bee6d 100644 --- a/Validator/WorkflowValidator.php +++ b/Validator/WorkflowValidator.php @@ -37,7 +37,7 @@ public function validate(Definition $definition, string $name) foreach ($definition->getTransitions() as $transition) { foreach ($transition->getFroms() as $from) { if (\in_array($transition->getName(), $places[$from])) { - throw new InvalidDefinitionException(sprintf('All transitions for a place must have an unique name. Multiple transitions named "%s" where found for place "%s" in workflow "%s".', $transition->getName(), $from, $name)); + throw new InvalidDefinitionException(\sprintf('All transitions for a place must have an unique name. Multiple transitions named "%s" where found for place "%s" in workflow "%s".', $transition->getName(), $from, $name)); } $places[$from][] = $transition->getName(); } @@ -49,13 +49,13 @@ public function validate(Definition $definition, string $name) foreach ($definition->getTransitions() as $transition) { if (1 < \count($transition->getTos())) { - throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" cannot store many places. But the transition "%s" has too many output (%d). Only one is accepted.', $name, $transition->getName(), \count($transition->getTos()))); + throw new InvalidDefinitionException(\sprintf('The marking store of workflow "%s" cannot store many places. But the transition "%s" has too many output (%d). Only one is accepted.', $name, $transition->getName(), \count($transition->getTos()))); } } $initialPlaces = $definition->getInitialPlaces(); if (2 <= \count($initialPlaces)) { - throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" cannot store many places. But the definition has %d initial places. Only one is supported.', $name, \count($initialPlaces))); + throw new InvalidDefinitionException(\sprintf('The marking store of workflow "%s" cannot store many places. But the definition has %d initial places. Only one is supported.', $name, \count($initialPlaces))); } } } diff --git a/Workflow.php b/Workflow.php index 818fbc2..dee280b 100644 --- a/Workflow.php +++ b/Workflow.php @@ -83,7 +83,7 @@ public function getMarking(object $subject, array $context = []): Marking // check if the subject is already in the workflow if (!$marking->getPlaces()) { if (!$this->definition->getInitialPlaces()) { - throw new LogicException(sprintf('The Marking is empty and there is no initial place for workflow "%s".', $this->name)); + throw new LogicException(\sprintf('The Marking is empty and there is no initial place for workflow "%s".', $this->name)); } foreach ($this->definition->getInitialPlaces() as $place) { $marking->mark($place); @@ -103,7 +103,7 @@ public function getMarking(object $subject, array $context = []): Marking $places = $this->definition->getPlaces(); foreach ($marking->getPlaces() as $placeName => $nbToken) { if (!isset($places[$placeName])) { - $message = sprintf('Place "%s" is not valid for workflow "%s".', $placeName, $this->name); + $message = \sprintf('Place "%s" is not valid for workflow "%s".', $placeName, $this->name); if (!$places) { $message .= ' It seems you forgot to add places to the current workflow.'; } @@ -319,8 +319,8 @@ private function guardTransition(object $subject, Marking $marking, Transition $ $event = new GuardEvent($subject, $marking, $transition, $this); $this->dispatcher->dispatch($event, WorkflowEvents::GUARD); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.guard', $this->name)); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.guard.%s', $this->name, $transition->getName())); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.guard', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.guard.%s', $this->name, $transition->getName())); return $event; } @@ -333,10 +333,10 @@ private function leave(object $subject, Transition $transition, Marking $marking $event = new LeaveEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::LEAVE); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.leave', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.leave', $this->name)); foreach ($places as $place) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.leave.%s', $this->name, $place)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.leave.%s', $this->name, $place)); } } @@ -354,8 +354,8 @@ private function transition(object $subject, Transition $transition, Marking $ma $event = new TransitionEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::TRANSITION); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.transition', $this->name)); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.transition.%s', $this->name, $transition->getName())); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.transition', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.transition.%s', $this->name, $transition->getName())); return $event->getContext(); } @@ -368,10 +368,10 @@ private function enter(object $subject, Transition $transition, Marking $marking $event = new EnterEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTER); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.enter', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.enter', $this->name)); foreach ($places as $place) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.enter.%s', $this->name, $place)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.enter.%s', $this->name, $place)); } } @@ -389,7 +389,7 @@ private function entered(object $subject, ?Transition $transition, Marking $mark $event = new EnteredEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ENTERED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.entered', $this->name)); $placeNames = []; if ($transition) { @@ -398,7 +398,7 @@ private function entered(object $subject, ?Transition $transition, Marking $mark $placeNames = $this->definition->getInitialPlaces(); } foreach ($placeNames as $placeName) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.entered.%s', $this->name, $placeName)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.entered.%s', $this->name, $placeName)); } } @@ -411,8 +411,8 @@ private function completed(object $subject, Transition $transition, Marking $mar $event = new CompletedEvent($subject, $marking, $transition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::COMPLETED); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed', $this->name)); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.completed', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.completed.%s', $this->name, $transition->getName())); } private function announce(object $subject, Transition $initialTransition, Marking $marking, array $context): void @@ -424,10 +424,10 @@ private function announce(object $subject, Transition $initialTransition, Markin $event = new AnnounceEvent($subject, $marking, $initialTransition, $this, $context); $this->dispatcher->dispatch($event, WorkflowEvents::ANNOUNCE); - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce', $this->name)); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.announce', $this->name)); foreach ($this->getEnabledTransitions($subject) as $transition) { - $this->dispatcher->dispatch($event, sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); + $this->dispatcher->dispatch($event, \sprintf('workflow.%s.announce.%s', $this->name, $transition->getName())); } } From afbcdbebf4e5e597795026601c9bacc03a5df2cb Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Tue, 24 Jun 2025 14:17:47 +0100 Subject: [PATCH 11/11] Fix various bool-type coercions --- Dumper/GraphvizDumper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dumper/GraphvizDumper.php b/Dumper/GraphvizDumper.php index 36a5be9..652e886 100644 --- a/Dumper/GraphvizDumper.php +++ b/Dumper/GraphvizDumper.php @@ -141,7 +141,7 @@ protected function findTransitions(Definition $definition, bool $withMetadata): /** * @internal */ - protected function addPlaces(array $places, float $withMetadata): string + protected function addPlaces(array $places, bool $withMetadata): string { $code = ''; @@ -303,7 +303,7 @@ protected function addAttributes(array $attributes): string * * @internal */ - protected function formatLabel(Definition $definition, string $withMetadata, array $options): string + protected function formatLabel(Definition $definition, bool $withMetadata, array $options): string { $currentLabel = $options['label'] ?? ''; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy