Skip to content
Permalink
Browse files

feature #29146 [Workflow] Added a context to `Workflow::apply()` (lyr…

…ixx)

This PR was merged into the 4.3-dev branch.

Discussion
----------

[Workflow] Added a context to `Workflow::apply()`

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #27925 (maybe #28253 and #28266)
| License       | MIT
| Doc PR        |

Commits
-------

7d5b7a3 [Workflow] Added a context to `Workflow::apply()`
  • Loading branch information...
lyrixx committed Mar 6, 2019
2 parents f8664e7 + 7d5b7a3 commit 5b38e1786301f57de3e988e78279e050c35c378d
@@ -268,7 +268,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
->fixXmlConfig('argument')
->children()
->enumNode('type')
->values(['multiple_state', 'single_state'])
->values(['multiple_state', 'single_state', 'method'])
->end()
->arrayNode('arguments')
->beforeNormalization()
@@ -614,7 +614,8 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
$definitionDefinition->addTag('workflow.definition', [
'name' => $name,
'type' => $type,
'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null,
'marking_store' => $workflow['marking_store']['type'] ?? null,
'single_state' => 'method' === ($workflow['marking_store']['type'] ?? null) && ($workflow['marking_store']['arguments'][0] ?? false),
]);
// Create MarkingStore
@@ -22,6 +22,7 @@

<service id="workflow.marking_store.multiple_state" class="Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore" abstract="true" />
<service id="workflow.marking_store.single_state" class="Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore" abstract="true" />
<service id="workflow.marking_store.method" class="Symfony\Component\Workflow\MarkingStore\MethodMarkingStore" abstract="true" />

<service id="workflow.registry" class="Symfony\Component\Workflow\Registry" />
<service id="Symfony\Component\Workflow\Registry" alias="workflow.registry" />
@@ -215,7 +215,7 @@ public function testWorkflows()
$workflowDefinition->getArgument(0),
'Places are passed to the workflow definition'
);
$this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state']]], $workflowDefinition->getTags());
$this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state', 'single_state' => false]]], $workflowDefinition->getTags());
$this->assertCount(4, $workflowDefinition->getArgument(1));
$this->assertSame('draft', $workflowDefinition->getArgument(2));
@@ -237,7 +237,7 @@ public function testWorkflows()
$stateMachineDefinition->getArgument(0),
'Places are passed to the state machine definition'
);
$this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state']]], $stateMachineDefinition->getTags());
$this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state', 'single_state' => false]]], $stateMachineDefinition->getTags());
$this->assertCount(9, $stateMachineDefinition->getArgument(1));
$this->assertSame('start', $stateMachineDefinition->getArgument(2));
@@ -5,6 +5,7 @@ CHANGELOG
-----

* Trigger `entered` event for subject entering in the Workflow for the first time
* Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature.

4.1.0
-----
@@ -59,6 +59,10 @@ private function createValidator($tag)
return new WorkflowValidator(true);
}
return new WorkflowValidator();
if ('multiple_state' === $tag['marking_store']) {
return new WorkflowValidator(false);
}
return new WorkflowValidator($tag['single_state'] ?? false);
}
}
@@ -36,8 +36,7 @@ public function getMarking($subject);
/**
* Sets a Marking to a subject.
*
* @param object $subject A subject
* @param Marking $marking A marking
* @param object $subject A subject
*/
public function setMarking($subject, Marking $marking);
public function setMarking($subject, Marking $marking, array $context = []);
}
@@ -0,0 +1,83 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Workflow\MarkingStore;
use Symfony\Component\Workflow\Exception\LogicException;
use Symfony\Component\Workflow\Marking;
/**
* MethodMarkingStore stores the marking with a subject's method.
*
* This store deals with a "single state" or "multiple state" Marking.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class MethodMarkingStore implements MarkingStoreInterface
{
private $singleState;
private $property;
/**
* @param string $property Used to determine methods to call
* The `getMarking` method will use `$subject->getProperty()`
* The `setMarking` method will use `$subject->setProperty(string|array $places, array $context = array())`
*/
public function __construct(bool $singleState = false, string $property = 'marking')
{
$this->singleState = $singleState;
$this->property = $property;
}
/**
* {@inheritdoc}
*/
public function getMarking($subject)
{
$method = 'get'.ucfirst($this->property);
if (!method_exists($subject, $method)) {
throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method));
}
$marking = $subject->{$method}();
if (!$marking) {
return new Marking();
}
if ($this->singleState) {
$marking = [$marking => 1];
}
return new Marking($marking);
}
/**
* {@inheritdoc}
*/
public function setMarking($subject, Marking $marking, array $context = [])
{
$marking = $marking->getPlaces();
if ($this->singleState) {
$marking = key($marking);
}
$method = 'set'.ucfirst($this->property);
if (!method_exists($subject, $method)) {
throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method));
}
$subject->{$method}($marking, $context);
}
}
@@ -46,7 +46,7 @@ public function getMarking($subject)
/**
* {@inheritdoc}
*/
public function setMarking($subject, Marking $marking)
public function setMarking($subject, Marking $marking, array $context = [])
{
$this->propertyAccessor->setValue($subject, $this->property, $marking->getPlaces());
}
@@ -51,7 +51,7 @@ public function getMarking($subject)
/**
* {@inheritdoc}
*/
public function setMarking($subject, Marking $marking)
public function setMarking($subject, Marking $marking, array $context = [])
{
$this->propertyAccessor->setValue($subject, $this->property, key($marking->getPlaces()));
}
@@ -0,0 +1,74 @@
<?php
namespace Symfony\Component\Workflow\Tests\MarkingStore;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
class MethodMarkingStoreTest extends TestCase
{
public function testGetSetMarkingWithMultipleState()
{
$subject = new Subject();
$markingStore = new MethodMarkingStore(false);
$marking = $markingStore->getMarking($subject);
$this->assertInstanceOf(Marking::class, $marking);
$this->assertCount(0, $marking->getPlaces());
$marking->mark('first_place');
$markingStore->setMarking($subject, $marking);
$this->assertSame(['first_place' => 1], $subject->getMarking());
$marking2 = $markingStore->getMarking($subject);
$this->assertEquals($marking, $marking2);
}
public function testGetSetMarkingWithSingleState()
{
$subject = new Subject();
$markingStore = new MethodMarkingStore(true);
$marking = $markingStore->getMarking($subject);
$this->assertInstanceOf(Marking::class, $marking);
$this->assertCount(0, $marking->getPlaces());
$marking->mark('first_place');
$markingStore->setMarking($subject, $marking);
$this->assertSame('first_place', $subject->getMarking());
$marking2 = $markingStore->getMarking($subject);
$this->assertEquals($marking, $marking2);
}
}
final class Subject
{
private $marking;
public function __construct($marking = null)
{
$this->marking = $marking;
}
public function getMarking()
{
return $this->marking;
}
public function setMarking($marking)
{
$this->marking = $marking;
}
}
@@ -143,7 +143,7 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr
/**
* {@inheritdoc}
*/
public function apply($subject, $transitionName)
public function apply($subject, $transitionName, array $context = [])
{
$marking = $this->getMarking($subject);
@@ -172,7 +172,7 @@ public function apply($subject, $transitionName)
$this->enter($subject, $transition, $marking);
$this->markingStore->setMarking($subject, $marking);
$this->markingStore->setMarking($subject, $marking, $context);
$this->entered($subject, $transition, $marking);
@@ -58,7 +58,7 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr
*
* @throws LogicException If the transition is not applicable
*/
public function apply($subject, $transitionName);
public function apply($subject, $transitionName, array $context = []);
/**
* Returns all enabled transitions.

0 comments on commit 5b38e17

Please sign in to comment.
You can’t perform that action at this time.