Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 48616a3

Browse filesBrowse files
[Workflow] Add support of UnitEnum and BackedEnum to workflow places
1 parent a1c9f10 commit 48616a3
Copy full SHA for 48616a3

19 files changed

+717
-204
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+56-8Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use Symfony\Component\Uid\Factory\UuidFactory;
4040
use Symfony\Component\Validator\Validation;
4141
use Symfony\Component\WebLink\HttpHeaderSerializer;
42+
use Symfony\Component\Workflow\Utils\PlaceEnumerationUtils;
4243
use Symfony\Component\Workflow\WorkflowEvents;
4344

4445
/**
@@ -396,7 +397,24 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
396397
->end()
397398
->arrayNode('initial_marking')
398399
->beforeNormalization()->castToArray()->end()
399-
->defaultValue([])
400+
->beforeNormalization()
401+
->ifTrue(function ($v) {
402+
foreach ($v as $value) {
403+
if (!is_scalar($value) && !$value instanceof \UnitEnum) {
404+
return true;
405+
}
406+
}
407+
408+
return false;
409+
})
410+
->thenInvalid('Initial marking must either be a scalar or an UnitEnum.')
411+
->end()
412+
->beforeNormalization()
413+
->always()
414+
->then(function ($places) {
415+
return array_map(static fn ($element) => PlaceEnumerationUtils::getPlaceKey($element), $places);
416+
})
417+
->end()
400418
->prototype('scalar')->end()
401419
->end()
402420
->variableNode('events_to_dispatch')
@@ -431,9 +449,9 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
431449
->always()
432450
->then(function ($places) {
433451
// It's an indexed array of shape ['place1', 'place2']
434-
if (isset($places[0]) && \is_string($places[0])) {
435-
return array_map(function (string $place) {
436-
return ['name' => $place];
452+
if (isset($places[0]) && (\is_string($places[0]) || $places[0] instanceof \UnitEnum)) {
453+
return array_map(function (string|\UnitEnum $place) {
454+
return ['name' => PlaceEnumerationUtils::getPlaceKey($place)];
437455
}, $places);
438456
}
439457

@@ -505,19 +523,49 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
505523
->example('is_fully_authenticated() and is_granted(\'ROLE_JOURNALIST\') and subject.getTitle() == \'My first article\'')
506524
->end()
507525
->arrayNode('from')
526+
->beforeNormalization()->castToArray()->end()
527+
->beforeNormalization()
528+
->ifTrue(function ($v) {
529+
foreach ($v as $value) {
530+
if (!is_scalar($value) && !$value instanceof \UnitEnum) {
531+
return true;
532+
}
533+
}
534+
535+
return false;
536+
})
537+
->thenInvalid('"From" places must either be scalars or UnitEnum.')
538+
->end()
508539
->beforeNormalization()
509-
->ifString()
510-
->then(function ($v) { return [$v]; })
540+
->always()
541+
->then(function ($places) {
542+
return array_map(static fn ($element) => PlaceEnumerationUtils::getPlaceKey($element), $places);
543+
})
511544
->end()
512545
->requiresAtLeastOneElement()
513546
->prototype('scalar')
514547
->cannotBeEmpty()
515548
->end()
516549
->end()
517550
->arrayNode('to')
551+
->beforeNormalization()->castToArray()->end()
552+
->beforeNormalization()
553+
->ifTrue(function ($v) {
554+
foreach ($v as $value) {
555+
if (!is_scalar($value) && !$value instanceof \UnitEnum) {
556+
return true;
557+
}
558+
}
559+
560+
return false;
561+
})
562+
->thenInvalid('"To" places must either be scalars or UnitEnum.')
563+
->end()
518564
->beforeNormalization()
519-
->ifString()
520-
->then(function ($v) { return [$v]; })
565+
->always()
566+
->then(function ($places) {
567+
return array_map(static fn ($element) => PlaceEnumerationUtils::getPlaceKey($element), $places);
568+
})
521569
->end()
522570
->requiresAtLeastOneElement()
523571
->prototype('scalar')

‎src/Symfony/Component/Workflow/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.1
5+
---
6+
7+
* Added support of UnitEnum and BackedEnum to Workflow places
8+
49
6.0
510
---
611

‎src/Symfony/Component/Workflow/Definition.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Definition.php
+14-11Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Workflow\Exception\LogicException;
1515
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
1616
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
17+
use Symfony\Component\Workflow\Utils\PlaceEnumerationUtils;
1718

1819
/**
1920
* @author Fabien Potencier <fabien@symfony.com>
@@ -28,11 +29,11 @@ final class Definition
2829
private MetadataStoreInterface $metadataStore;
2930

3031
/**
31-
* @param string[] $places
32-
* @param Transition[] $transitions
33-
* @param string|string[]|null $initialPlaces
32+
* @param string[]|\UnitEnum[] $places
33+
* @param Transition[] $transitions
34+
* @param string|string[]|\UnitEnum|\UnitEnum[]|null $initialPlaces
3435
*/
35-
public function __construct(array $places, array $transitions, string|array $initialPlaces = null, MetadataStoreInterface $metadataStore = null)
36+
public function __construct(array $places, array $transitions, string|\UnitEnum|array $initialPlaces = null, MetadataStoreInterface $metadataStore = null)
3637
{
3738
foreach ($places as $place) {
3839
$this->addPlace($place);
@@ -52,7 +53,7 @@ public function __construct(array $places, array $transitions, string|array $ini
5253
*/
5354
public function getInitialPlaces(): array
5455
{
55-
return $this->initialPlaces;
56+
return array_map(static fn ($element) => PlaceEnumerationUtils::getTypedValue($element), $this->initialPlaces);
5657
}
5758

5859
/**
@@ -76,43 +77,45 @@ public function getMetadataStore(): MetadataStoreInterface
7677
return $this->metadataStore;
7778
}
7879

79-
private function setInitialPlaces(string|array $places = null)
80+
private function setInitialPlaces(string|\UnitEnum|array $places = null)
8081
{
8182
if (!$places) {
8283
return;
8384
}
8485

85-
$places = (array) $places;
86+
$places = array_map(static fn ($element) => PlaceEnumerationUtils::getPlaceKey($element), \is_array($places) ? $places : [$places]);
8687

8788
foreach ($places as $place) {
8889
if (!isset($this->places[$place])) {
89-
throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place));
90+
throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', PlaceEnumerationUtils::getPlaceKey($place)));
9091
}
9192
}
9293

9394
$this->initialPlaces = $places;
9495
}
9596

96-
private function addPlace(string $place)
97+
private function addPlace(string|\UnitEnum $place)
9798
{
9899
if (!\count($this->places)) {
99-
$this->initialPlaces = [$place];
100+
$this->initialPlaces = [PlaceEnumerationUtils::getPlaceKey($place)];
100101
}
101102

102-
$this->places[$place] = $place;
103+
$this->places[PlaceEnumerationUtils::getPlaceKey($place)] = $place;
103104
}
104105

105106
private function addTransition(Transition $transition)
106107
{
107108
$name = $transition->getName();
108109

109110
foreach ($transition->getFroms() as $from) {
111+
$from = PlaceEnumerationUtils::getPlaceKey($from);
110112
if (!isset($this->places[$from])) {
111113
throw new LogicException(sprintf('Place "%s" referenced in transition "%s" does not exist.', $from, $name));
112114
}
113115
}
114116

115117
foreach ($transition->getTos() as $to) {
118+
$to = PlaceEnumerationUtils::getPlaceKey($to);
116119
if (!isset($this->places[$to])) {
117120
throw new LogicException(sprintf('Place "%s" referenced in transition "%s" does not exist.', $to, $name));
118121
}

‎src/Symfony/Component/Workflow/EventListener/AuditTrailListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/EventListener/AuditTrailListener.php
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Psr\Log\LoggerInterface;
1515
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1616
use Symfony\Component\Workflow\Event\Event;
17+
use Symfony\Component\Workflow\Utils\PlaceEnumerationUtils;
1718

1819
/**
1920
* @author Grégoire Pineau <lyrixx@lyrixx.info>
@@ -30,7 +31,7 @@ public function __construct(LoggerInterface $logger)
3031
public function onLeave(Event $event)
3132
{
3233
foreach ($event->getTransition()->getFroms() as $place) {
33-
$this->logger->info(sprintf('Leaving "%s" for subject of class "%s" in workflow "%s".', $place, \get_class($event->getSubject()), $event->getWorkflowName()));
34+
$this->logger->info(sprintf('Leaving "%s" for subject of class "%s" in workflow "%s".', PlaceEnumerationUtils::getPlaceKey($place), \get_class($event->getSubject()), $event->getWorkflowName()));
3435
}
3536
}
3637

@@ -42,7 +43,7 @@ public function onTransition(Event $event)
4243
public function onEnter(Event $event)
4344
{
4445
foreach ($event->getTransition()->getTos() as $place) {
45-
$this->logger->info(sprintf('Entering "%s" for subject of class "%s" in workflow "%s".', $place, \get_class($event->getSubject()), $event->getWorkflowName()));
46+
$this->logger->info(sprintf('Entering "%s" for subject of class "%s" in workflow "%s".', PlaceEnumerationUtils::getPlaceKey($place), \get_class($event->getSubject()), $event->getWorkflowName()));
4647
}
4748
}
4849

‎src/Symfony/Component/Workflow/Marking.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/Marking.php
+23-10Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Workflow;
1313

14+
use Symfony\Component\Workflow\Utils\PlaceEnumerationUtils;
15+
1416
/**
1517
* Marking contains the place of every tokens.
1618
*
@@ -22,33 +24,44 @@ class Marking
2224
private ?array $context = null;
2325

2426
/**
25-
* @param int[] $representation Keys are the place name and values should be 1
27+
* @param int[]|\UnitEnum[] $representation Keys are the place name and values should be 1, unless UnitEnums
28+
* are used as workflow places
2629
*/
2730
public function __construct(array $representation = [])
2831
{
29-
foreach ($representation as $place => $nbToken) {
30-
$this->mark($place);
32+
foreach ($representation as $place => $token) {
33+
$this->mark($token instanceof \UnitEnum ? $token : $place);
3134
}
3235
}
3336

34-
public function mark(string $place)
37+
public function mark(string|\UnitEnum $place)
3538
{
36-
$this->places[$place] = 1;
39+
$this->places[PlaceEnumerationUtils::getPlaceKey($place)] = 1;
3740
}
3841

39-
public function unmark(string $place)
42+
public function unmark(string|\UnitEnum $place)
4043
{
41-
unset($this->places[$place]);
44+
unset($this->places[PlaceEnumerationUtils::getPlaceKey($place)]);
4245
}
4346

44-
public function has(string $place)
47+
public function has(string|\UnitEnum $place)
4548
{
46-
return isset($this->places[$place]);
49+
return isset($this->places[PlaceEnumerationUtils::getPlaceKey($place)]);
4750
}
4851

4952
public function getPlaces()
5053
{
51-
return $this->places;
54+
$places = [];
55+
foreach ($this->places as $key => $value) {
56+
$typedKey = PlaceEnumerationUtils::getTypedValue($key);
57+
if ($typedKey instanceof \UnitEnum) {
58+
$places[$key] = $typedKey;
59+
} else {
60+
$places[$typedKey] = 1;
61+
}
62+
}
63+
64+
return $places;
5265
}
5366

5467
/**

‎src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php
+23-4Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Workflow\Exception\LogicException;
1515
use Symfony\Component\Workflow\Marking;
16+
use Symfony\Component\Workflow\Utils\PlaceEnumerationUtils;
1617

1718
/**
1819
* MethodMarkingStore stores the marking with a subject's method.
@@ -61,10 +62,17 @@ public function getMarking(object $subject): Marking
6162
}
6263

6364
if ($this->singleState) {
64-
$marking = [(string) $marking => 1];
65+
$markingRepresentation = [PlaceEnumerationUtils::getPlaceKey($marking) => 1];
66+
} else {
67+
$markingRepresentation = [];
68+
foreach ($marking as $key => $item) {
69+
// When using enumerations, as the enumeration case can't be used as an array key, the value is actually
70+
// stored in the item instead of the key.
71+
$markingRepresentation[PlaceEnumerationUtils::getPlaceKey($item instanceof \UnitEnum ? $item : $key)] = 1;
72+
}
6573
}
6674

67-
return new Marking($marking);
75+
return new Marking($markingRepresentation);
6876
}
6977

7078
/**
@@ -75,7 +83,18 @@ public function setMarking(object $subject, Marking $marking, array $context = [
7583
$marking = $marking->getPlaces();
7684

7785
if ($this->singleState) {
78-
$marking = key($marking);
86+
$markingResult = PlaceEnumerationUtils::getTypedValue(key($marking));
87+
} else {
88+
$markingResult = [];
89+
foreach ($marking as $key => $item) {
90+
$value = PlaceEnumerationUtils::getTypedValue($key);
91+
if ($value instanceof \UnitEnum) {
92+
// UnitEnum can't be used as array key, put it as a simple value without specific index.
93+
$markingResult[] = $value;
94+
} else {
95+
$markingResult[$value] = 1;
96+
}
97+
}
7998
}
8099

81100
$method = 'set'.ucfirst($this->property);
@@ -84,6 +103,6 @@ public function setMarking(object $subject, Marking $marking, array $context = [
84103
throw new LogicException(sprintf('The method "%s::%s()" does not exist.', get_debug_type($subject), $method));
85104
}
86105

87-
$subject->{$method}($marking, $context);
106+
$subject->{$method}($markingResult, $context);
88107
}
89108
}
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Symfony\Component\Workflow\Tests;
4+
5+
enum AlphabeticalEnum: string
6+
{
7+
case A = 'a';
8+
case B = 'b';
9+
case C = 'c';
10+
case D = 'd';
11+
case E = 'e';
12+
case F = 'f';
13+
case G = 'g';
14+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.