8000 [Workflow] added support for multiple tokens · symfony/symfony@37b256c · GitHub
[go: up one dir, main page]

Skip to content

Commit 37b256c

Browse files
committed
[Workflow] added support for multiple tokens
1 parent 7c47114 commit 37b256c

File tree

7 files changed

+211
-8
lines changed

7 files changed

+211
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
282282
->end()
283283
->end()
284284
->end()
285+
->booleanNode('use_tokens')->defaultFalse()->end()
285286
->arrayNode('places')
286287
->isRequired()
287288
->requiresAtLeastOneElement()

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,9 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
450450
$workflowDefinition->replaceArgument(1, $markingStoreDefinition);
451451
}
452452
$workflowDefinition->replaceArgument(3, $name);
453+
if ('workflow' === $type) {
454+
$workflowDefinition->replaceArgument(4, $workflow['use_tokens']);
455+
}
453456

454457
// Store to container
455458
$workflowId = sprintf('%s.%s', $type, $name);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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\EventListener;
13+
14+
use Symfony\Component\Workflow\Event\GuardEvent;
15+
16+
/**
17+
* @author Jules Pietri <jules@heahprod.com>
18+
*/
19+
class WorkflowListener
20+
{
21+
public function __invoke(GuardEvent $event)
22+
{
23+
$marking = $event->getMarking();
24+
25+
foreach ($event->getTransition()->getTos() as $to) {
26+
if (!$marking->has($to)) {
27+
return;
28+
}
29+
}
30+
31+
$event->setBlocked(true);
32+
}
33+
}

src/Symfony/Component/Workflow/MultipleStateMarking.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ class MultipleStateMarking extends Marking
2525
public function __construct(array $representation = array())
2626
{
2727
foreach ($representation as $place => $nbToken) {
28-
$this->mark($place);
28+
for ($i = 0; $i < $nbToken; ++$i) {
29+
$this->mark($place);
30+
}
2931
}
3032
}
3133

@@ -34,16 +36,26 @@ public function __construct(array $representation = array())
3436
*/
3537
public function mark($place)
3638
{
37-
if (!isset($this->places[$place])) {
38-
$this->places[$place] = 1;
39+
if (isset($this->places[$place])) {
40+
$this->places[$place] += 1;
41+
42+
return;
3943
}
44+
45+
$this->places[$place] = 1;
4046
}
4147

4248
/**
4349
* {@inheritdoc}
4450
*/
4551
public function unmark($place)
4652
{
53+
if (isset($this->places[$place]) && $this->places[$place] > 1) {
54+
$this->places[$place] -= 1;
55+
56+
return;
57+
}
58+
4759
unset($this->places[$place]);
4860
}
4961
}

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,35 @@ public function testGetSetMultipleStateMarking()
8888
$marking3 = $markingStore->getMarking($subject);
8989

9090
$this->assertEquals($marking2, $marking3);
91+
92+
$marking3->mark('second_place');
93+
94+
$markingStore->setMarking($subject, $marking3);
95+
96+
$this->assertSame(array('first_place' => 1, 'second_place' => 2), $subject->myMarks);
97+
98+
$marking4 = $markingStore->getMarking($subject);
99+
100+
$this->assertEquals($marking3, $marking4);
101+
102+
$marking4->unmark('second_place');
103+
104+
$markingStore->setMarking($subject, $marking4);
105+
106+
$this->assertSame(array('first_place' => 1, 'second_place' => 1), $subject->myMarks);
107+
108+
$marking5 = $markingStore->getMarking($subject);
109+
110+
$this->assertEquals($marking4, $marking5);
111+
112+
$marking5->unmark('first_place');
113+
114+
$markingStore->setMarking($subject, $marking5);
115+
116+
$this->assertSame(array('second_place' => 1), $subject->myMarks);
117+
118+
$marking6 = $markingStore->getMarking($subject);
119+
120+
$this->assertEquals($marking5, $marking6);
91121
}
92122
}

src/Symfony/Component/Workflow/Tests/WorkflowTest.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ public function testCan()
107107
$this->assertFalse($workflow->can($subject, 't2'));
108108
}
109109

110+
public function testCannotHaveManyTokens()
111+
{
112+
$definition = $this->createComplexWorkflow();
113+
$subject = new \stdClass();
114+
$subject->marking = array('a' => 1, 'b' => 1, 'c' => 1);
115+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore());
116+
117+
$this->assertFalse($workflow->can($subject, 't1'));
118+
}
119+
120+
public function testCanUsingTokens()
121+
{
122+
$definition = $this->createComplexWorkflow();
123+
$subject = new \stdClass();
124+
$subject->marking = array('a' => 1, 'b' => 1, 'c' => 1);
125+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, null, true);
126+
127+
$this->assertTrue($workflow->can($subject, 't1'));
128+
}
129+
110130
public function testCanWithGuard()
111131
{
112132
$definition = $this->createComplexWorkflow();
@@ -184,6 +204,40 @@ public function testApplyWithEventDispatcher()
184204
$this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents);
185205
}
186206

207+
public function testApplyWithoutTokens()
208+
{
209+
$definition = $this->createComplexWorkflow();
210+
$subject = new \stdClass();
211+
$subject->marking = array('a' => 1, 'b' => 1);
212+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, 'workflow_name');
213+
214+
foreach ($workflow->getEnabledTransitions($subject) as $transition) {
215+
$workflow->apply($subject, $transition->getName());
216+
}
217+
218+
$this->assertSame(array('d' => 1), $subject->marking);
219+
}
220+
221+
public function testApplyWithTokens()
222+
{
223+
$definition = $this->createComplexWorkflow();
224+
$subject = new \stdClass();
225+
$subject->marking = array('f' => 2);
226+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, 'workflow_name', true);
227+
228+
foreach ($workflow->getEnabledTransitions($subject) as $transition) {
229+
$workflow->apply($subject, $transition->getName());
230+
}
231+
232+
$this->assertSame(array('f' => 1, 'g' => 1), $subject->marking);
233+
234+
foreach ($workflow->getEnabledTransitions($subject) as $transition) {
235+
$workflow->apply($subject, $transition->getName());
236+
}
237+
238+
$this->assertSame(array('g' => 2), $subject->marking);
239+
}
240+
187241
public function testGetEnabledTransitions()
188242
{
189243
$definition = $this->createComplexWorkflow();
@@ -209,6 +263,52 @@ public function testGetEnabledTransitions()
209263
$this->assertSame('t5', $transitions[0]->getName());
210264
}
211265

266+
public function testGetEnabledTransitionDoesNotExceedOneToken()
267+
{
268+
$definition = $this->createComplexWorkflow();
269+
$subject = new \stdClass();
270+
$subject->marking = array('a' => true, 'b' => true, 'c' => true);
271+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, 'workflow_name');
272+
273+
$transitions = $workflow->getEnabledTransitions($subject);
274+
// "a" cannot go in "b" or "c" as they're already marked
275+
$this->assertCount(1, $transitions);
276+
}
277 10000 +
278+
public function testGetEnabledTransitionUsingTokens()
279+
{
280+
$definition = $this->createComplexWorkflow();
281+
$subject = new \stdClass();
282+
$subject->marking = array('a' => 1, 'b' => 1, 'c' => 1);
283+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, 'workflow_name', true);
284+
285+
$transitions = $workflow->getEnabledTransitions($subject);
286+
$this->assertCount(2, $transitions);
287+
288+
foreach ($transitions as $transition) {
289+
$workflow->apply($subject, $transition->getName());
290+
}
291+
292+
$this->assertSame(array('b' => 1, 'c' => 1, 'd' => 1), $subject->marking);
293+
}
294+
295+
public function testGetEnabledTransitionUsingTokensWithMultipleTokens()
296+
{
297+
$definition = $this->createComplexWorkflow();
298+
$subject = new \stdClass();
299+
$subject->marking = array('b' => 2, 'c' => 1);
300+
$workflow = new Workflow($definition, new PropertyAccessMarkingStore(), null, 'workflow_name', true);
301+
302+
$transitions = $workflow->getEnabledTransitions($subject);
303+
$this->assertCount(1, $transitions);
304+
305+
foreach ($transitions as $transition) {
306+
$workflow->apply($subject, $transition->getName());
307+
}
308+
309+
$this->assertSame(array('b' => 1, 'd' => 1), $subject->marking);
310+
}
311+
212312
protected function createComplexWorkflow()
213313
{
214314
$builder = new DefinitionBuilder();

src/Symfony/Component/Workflow/Workflow.php

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111

1212
namespace Symfony\Component\Workflow;
1313

14+
use Symfony\Component\EventDispatcher\EventDispatch F41A er;
1415
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1516
use Symfony\Component\Workflow\Event\Event;
1617
use Symfony\Component\Workflow\Event\GuardEvent;
18+
use Symfony\Component\Workflow\EventListener\WorkflowListener;
1719
use Symfony\Component\Workflow\Exception\LogicException;
1820
use Symfony\Component\Workflow\MarkingStore\MarkingStore;
1921
use Symfony\Component\Workflow\MarkingStore\PropertyAccessMarkingStore;
@@ -29,13 +31,30 @@ class Workflow
2931
private $markingStore;
3032
private $dispatcher;
3133
private $name;
34+
private $useTokens;
3235

33-
public function __construct(Definition $definition, MarkingStore $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed')
36+
/**
37+
* @param Definition $definition
38+
* @param MarkingStore|null $markingStore
39+
* @param EventDispatcherInterface|null $dispatcher
40+
* @param string $name
41+
* @param bool $useTokens
42+
*/
43+
public function __construct(Definition $definition, MarkingStore $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed', $useTokens = false)
3444
{
3545
$this->definition = $definition;
3646
$this->markingStore = $markingStore ?: new PropertyAccessMarkingStore();
3747
$this->dispatcher = $dispatcher;
3848
$this->name = $name;
49+
$this->useTokens = (bool) $useTokens;
50+
51+
if (!$useTokens) {
52+
if (null === $dispatcher) {
53+
$this->dispatcher = new EventDispatcher();
54+
}
55+
56+
$this->dispatcher->addListener(sprintf('workflow.%s.guard', $name), new WorkflowListener());
57+
}
3958
}
4059

4160
/**
@@ -230,10 +249,12 @@ private function enter($subject, Transition $transition, Marking $marking)
230249
}
231250

232251
foreach ($transition->getTos() as $place) {
233-
$marking->mark($place);
252+
if (!$marking->has($place) || $this->useTokens) {
253+
$marking->mark($place);
234254

235-
if (null !== $this->dispatcher) {
236-
$this->dispatcher->dispatch(sprintf('workflow.%s.enter.%s', $this->name, $place), $event);
255+
if (null !== $this->dispatcher) {
256+
$this->dispatcher->dispatch(sprintf('workflow.%s.enter.%s', $this->name, $place), $event);
257+
}
237258
}
238259
}
239260
}
@@ -286,9 +307,12 @@ private function getTransitions($transitionName)
286307
*/
287308
private function getTransitionForSubject($subject, Marking $marking, array $transitions)
288309
{
310+
$strategy = $this->markingStore->getStrategy();
289311
foreach ($transitions as $transition) {
290312
foreach ($transition->getFroms() as $place) {
291-
if (!$marking->has($place)) {
313+
if ($marking->has($place) && Marking::STRATEGY_MULTIPLE_STATE === $strategy) {
314+
break;
315+
} elseif (!$marking->has($place)) {
292316
continue 2;
293317
}
294318
}

0 commit comments

Comments
 (0)
0