8000 [Workflow] Add support for storing the marking in a property · symfony/symfony@97e97ad · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 97e97ad

Browse files
committed
[Workflow] Add support for storing the marking in a property
1 parent 86c41bb commit 97e97ad

File tree

16 files changed

+276
-14
lines changed

16 files changed

+276
-14
lines changed

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Add native return type to `Translator` and to `Application::reset()`
88
* Deprecate the integration of Doctrine annotations, either uninstall the `doctrine/annotations` package or disable the integration by setting `framework.annotations` to `false`
9+
* Add support for `PropertiesMarkingStore` in the workflow configuration
910

1011
6.3
1112
---

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

+4-1
9E88
Original file line numberDiff line numberDiff line change
@@ -403,11 +403,14 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode): void
403403
->arrayNode('marking_store')
404404
->children()
405405
->enumNode('type')
406-
->values(['method'])
406+
->values(['method', 'properties'])
407407
->end()
408408
->scalarNode('property')
409409
->defaultValue('marking')
410410
->end()
411+
->scalarNode('context_property')
412+
->defaultValue('markingContext')
413+
->end()
411414
->scalarNode('service')
412415
->cannotBeEmpty()
413416
->end()

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -998,12 +998,20 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
998998

999999
// Create MarkingStore
10001000
$markingStoreDefinition = null;
1001-
if (isset($workflow['marking_store']['type'])) {
1001+
$markingStoreType = $workflow['marking_store']['type'] ?? null;
1002+
if ('method' === $markingStoreType) {
10021003
$markingStoreDefinition = new ChildDefinition('workflow.marking_store.method');
10031004
$markingStoreDefinition->setArguments([
10041005
'state_machine' === $type, // single state
10051006
$workflow['marking_store']['property'],
10061007
]);
1008+
} elseif ('properties' === $markingStoreType) {
1009+
$markingStoreDefinition = new ChildDefinition('workflow.marking_store.properties');
1010+
$markingStoreDefinition->setArguments([
1011+
'state_machine' === $type, // single state
1012+
$workflow['marking_store']['property'],
1013+
$workflow['marking_store']['context_property'],
1014+
]);
10071015
} elseif (isset($workflow['marking_store']['service'])) {
10081016
$markingStoreDefinition = new Reference($workflow['marking_store']['service']);
10091017
}

src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd

+2
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,13 @@
443443
<xsd:attribute name="type" type="marking_store_type" />
444444
<xsd:attribute name="service" type="xsd:string" />
445445
<xsd:attribute name="property" type="xsd:string" />
446+
<xsd:attribute name="context_property" type="xsd:string" />
446447
</xsd:complexType>
447448

448449
<xsd:simpleType name="marking_store_type">
449450
<xsd:restriction base="xsd:string">
450451
<xsd:enumeration value="method" />
452+
<xsd:enumeration value="properties" />
451453
</xsd:restriction>
452454
</xsd:simpleType>
453455

src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.php

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Symfony\Component\Workflow\EventListener\ExpressionLanguage;
1515
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
16+
use Symfony\Component\Workflow\MarkingStore\PropertiesMarkingStore;
1617
use Symfony\Component\Workflow\Registry;
1718
use Symfony\Component\Workflow\StateMachine;
1819
use Symfony\Component\Workflow\Workflow;
@@ -39,6 +40,8 @@
3940
->abstract()
4041
->set('workflow.marking_store.method', MethodMarkingStore::class)
4142
->abstract()
43+
->set('workflow.marking_store.properties', PropertiesMarkingStore::class)
44+
->abstract()
4245
->set('.workflow.registry', Registry::class)
4346
->alias(Registry::class, '.workflow.registry')
4447
->deprecate('symfony/workflow', '6.2', 'The "%alias_id%" alias is deprecated, inject the workflow directly.')

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php

+5
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@
4848
FrameworkExtensionTestCase::class,
4949
],
5050
'initial_marking' => 'start',
51+
'marking_store' => [
52+
'type' => 'properties',
53+
'property' => 'state',
54+
'context_property' => 'stateContext',
55+
],
5156
'metadata' => [
5257
'title' => 'workflow title',
5358
],

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<framework:workflow name="pull_request">
4646
<framework:audit-trail enabled="false"/>
4747
<framework:initial-marking>start</framework:initial-marking>
48+
<framework:marking-store type="properties" property="state" context_property="stateContext" />
4849
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTestCase</framework:support>
4950
<framework:place name="start">
5051
<framework:metadata>

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ framework:
3535
supports:
3636
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTestCase
3737
initial_marking: start
38+
marking_store:
39+
type: properties
40+
property: state
41+
context_property: stateContext
3842
metadata:
3943
title: workflow title
4044
places:

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php

+7
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ public function testWorkflows()
300300
$args = $container->getDefinition('workflow.article')->getArguments();
301301
$this->assertArrayHasKey('index_0', $args);
302302
$this->assertArrayHasKey('index_1', $args);
303+
$this->assertNull($args['index_1']);
303304
$this->assertArrayHasKey('index_3', $args);
304305
$this->assertArrayHasKey('index_4', $args);
305306
$this->assertNull($args['index_4'], 'Workflows has eventsToDispatch=null');
@@ -333,6 +334,12 @@ public function testWorkflows()
333334

334335
$this->assertTrue($container->hasDefinition('state_machine.pull_request'), 'State machine is registered as a service');
335336
$this->assertSame('state_machine.abstract', $container->getDefinition('state_machine.pull_request')->getParent());
337+
338+
$markingStoreDefinition = $container->getDefinition('state_machine.pull_request')->getArguments()['index_1'];
339+
$this->assertInstanceOf(ChildDefinition::class, $markingStoreDefinition);
340+
$this->assertSame('workflow.marking_store.properties', $markingStoreDefinition->getParent());
341+
$this->assertSame([true, 'state', 'stateContext'], $markingStoreDefinition->getArguments());
342+
336343
$this->assertTrue($container->hasDefinition('state_machine.pull_request.definition'), 'State machine definition is registered as a service');
337344

338345
$this->assertSame(['workflow' => [['name' => 'pull_request']], 'workflow.state_machine' => [['name' => 'pull_request']]], $container->getDefinition('state_machine.pull_request')->getTags());

src/Symfony/Bundle/FrameworkBundle/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"symfony/twig-bundle": "<5.4",
100100
"symfony/validator": "<6.3",
101101
"symfony/web-profiler-bundle": "<5.4",
102-
"symfony/workflow": "<5.4"
102+
"symfony/workflow": "<6.4"
103103
},
104104
"autoload": {
105105
"psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" },

src/Symfony/Component/Workflow/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ CHANGELOG
66

77
* Add `with-metadata` option to the `workflow:dump` command to include places,
88
transitions and workflow's metadata into dumped graph
9+
* Add `PropertiesMarkingStore` to store marking directly to the suject's
10+
properties
911

1012
6.2
1113
---

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

+6-9
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,24 @@
2020
* This store deals with a "single state" or "multiple state" Marking.
2121
*
2222
* "single state" Marking means a subject can be in one and only one state at
23-
* the same time. Use it with state machine.
23+
* the same time. Use it with state machine. It uses a string to store the marking
2424
*
2525
* "multiple state" Marking means a subject can be in many states at the same
26-
* time. Use it with workflow.
26+
* time. Use it with workflow. It uses an array to store the marking
2727
*
2828
* @author Grégoire Pineau <lyrixx@lyrixx.info>
2929
*/
3030
final class MethodMarkingStore implements MarkingStoreInterface
3131
{
32-
private bool $singleState;
33-
private string $property;
34-
3532
/**
3633
* @param string $property Used to determine methods to call
3734
* The `getMarking` method will use `$subject->getProperty()`
3835
* The `setMarking` method will use `$subject->setProperty(string|array $places, array $context = array())`
3936
*/
40-
public function __construct(bool $singleState = false, string $property = 'marking')
41-
{
42-
$this->singleState = $singleState;
43-
$this->property = $property;
37+
public function __construct(
38+
private bool $singleState = false,
39+
private string $property = 'marking',
40+
) {
4441
}
4542

4643
public function getMarking(object $subject): Marking
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Workflow\MarkingStore;
13+
14+
use Symfony\Component\Workflow\Exception\LogicException;
15+
use Symfony\Component\Workflow\Marking;
16+
17+
/**
18+
* PropertiesMarkingStore stores the marking with a subject's properties.
19+
*
20+
* This store deals with a "single state" or "multiple state" Marking.
21+
*
22+
* "single state" Marking means a subject can be in one and only one state at
23+
* the same time. Use it with state machine. It uses a string to store the marking
24+
*
25+
* "multiple state" Marking means a subject can be in many states at the same
26+
* time. Use it with workflow. It uses an array to store the marking
27+
*
28+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
29+
*/
30+
final class PropertiesMarkingStore implements MarkingStoreInterface
31+
{
32+
public function __construct(
33+
private bool $singleState = false,
34+
private string $property = 'marking',
35+
private ?string $contextProperty = 'markingContext',
36+
) {
37+
}
38+
39+
public function getMarking(object $subject): Marking
40+
{
41+
if (!property_exists($subject, $this->property)) {
42+
throw new LogicException(sprintf('The property "%s::$%s" does not exist.', get_debug_type($subject), $this->property));
43+
}
44+
45+
$marking = null;
46+
try {
47+
$marking = $subject->{$this->property};
48+
} catch (\Error $e) {
49+
$unInitializedPropertyMessage = sprintf('Typed property %s::$%s must not be accessed before initialization', get_debug_type($subject), $this->property);
50+
if ($e->getMessage() !== $unInitializedPropertyMessage) {
51+
throw $e;
52+
}
53+
}
54+
55+
if (null === $marking) {
56+
return new Marking();
57+
}
58+
59+
if ($this->singleState) {
60+
$marking = [(string) $marking => 1];
61+
} elseif (!\is_array($marking)) {
62+
throw new LogicException(sprintf('The property "%s::$%s" did not return an array and the Workflow\'s Marking store is instantiated with $singleState=false.', get_debug_type($subject), $this->property));
63+
}
64+
65+
return new Ma 10000 rking($marking);
66+
}
67+
68+
public function setMarking(object $subject, Marking $marking, array $context = []): void
69+
{
70+
$marking = $marking->getPlaces();
71+
72+
if ($this->singleState) {
73+
$marking = key($marking);
74+
}
75+
76+
if (!property_exists($subject, $this->property)) {
77+
throw new LogicException(sprintf('The property "%s::$%s" does not exist.', get_debug_type($subject), $this->property));
78+
}
79+
$subject->{$this->property} = $marking;
80+
81+
if (null !== $this->contextProperty) {
82+
if (!property_exists($subject, $this->contextProperty)) {
83+
throw new LogicException(sprintf('The property "%s::$%s" does not exist.', get_debug_type($subject), $this->contextProperty));
84+
}
85+
$subject->{$this->contextProperty} = $context;
86+
}
87+
}
88+
}

src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ public function testGetSetMarkingWithMultipleState()
2929

3030
$marking->mark('first_place');
3131

32-
$markingStore->setMarking($subject, $marking);
32+
$markingStore->setMarking($subject, $marking, ['foo' => 'bar']);
3333

3434
$this->assertSame(['first_place' => 1], $subject->getMarking());
35+
$this->assertSame(['foo' => 'bar'], $subject->getContext());
3536

3637
$marking2 = $markingStore->getMarking($subject);
3738

@@ -50,11 +51,12 @@ public function testGetSetMarkingWithSingleState()
5051

5152
$marking->mark('first_place');
5253

53-
$markingStore->setMarking($subject, $marking);
54+
$markingStore->setMarking($subject, $marking, ['foo' => 'bar']);
5455

5556
$this->assertSame('first_place', $subject->getMarking());
5657

5758
$marking2 = $markingStore->getMarking($subject);
59+
$this->assertSame(['foo' => 'bar'], $subject->getContext());
5860

5961
$this->assertEquals($marking, $marking2);
6062
}

0 commit comments

Comments
 (0)
0