feature #26092 [Workflow] Add a MetadataStore to fetch some metadata (lyrixx)
This PR was merged into the 4.1-dev branch.
Discussion
----------
[Workflow] Add a MetadataStore to fetch some metadata
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | yes (little)
| Deprecations? | yes
| Tests pass? | yes
| Fixed tickets | #23257
| License | MIT
| Doc PR | TODO
---
This is an attempt to fix #23257. I first started to implement
`Ẁorkflow::getMetadata()`, `Transition::getMetadata()` and
`Place::getMetadata()`. **BUT**, there are no `Place` class. For now it's just a
`string`. So dealing with BC is a nightmare.
So I tried to find another way to fix the issue. [This
comment](https://github.com/symfony/symfony/issues/23257#issuecomment-315551397)
summary well the two options. But this PR is (will be) a mix of theses 2
options.
First it will be possible to configure the workflow/metadata like this:
```yaml
blog_publishing:
supports:
- AppBundle\Entity\BlogPost
metada:
label: Blog publishing
description: Manages blog publishing
places:
draft:
metadata:
description: Blog has just been created
color: grey
review:
metadata:
description: Blog is waiting for review
color: blue
transitions:
to_review:
from: draft
to: review
metadata:
label: Submit for review
route: admin.blog.review
```
I think is very good for the DX. Simple to understand.
All metadata will live in a `MetadataStoreInterface`. If metadata are set via
the configuration (workflows.yaml), then we will use the
`InMemoryMetadataStore`.
Having a MetadataStoreInterface allow user to get dynamic value for a place /
transitions. It's really flexible. (But is it a valid use case ?)
Then, to retrieve these data, the end user will have to write this code:
```php
public function onReview(Event $event) {
$metadataStore = $event->getWorkflow()->getMetadataStore();
foreach ($event->getTransition()->getTos() as $place) {
$this->flashbag->add('info', $metadataStore->getPlaceMetadata($place)->get('description'));
}
}
```
Note: I might add some shortcut to the Event class
or in twig:
```jinja
{% for transition in workflow_transitions(post) %}
<a href="{{ workflow_metadata_transition(post, route) }}">
{{ workflow_metadata_transition(post, transition) }}
</a>
{% endfor %}
```
---
WDYT ?
Should I continue this way, or should I introduce a `Place` class (there will be
so many deprecation ...)
Commits
-------
bd1f2c8583
[Workflow] Add a MetadataStore
This commit is contained in:
commit
07a2f6cef4
@ -104,3 +104,4 @@ Workflow
|
||||
* Deprecated the `add` method in favor of the `addWorkflow` method in `Workflow\Registry`.
|
||||
* Deprecated `SupportStrategyInterface` in favor of `WorkflowSupportStrategyInterface`.
|
||||
* Deprecated the class `ClassInstanceSupportStrategy` in favor of the class `InstanceOfSupportStrategy`.
|
||||
* Deprecated passing the workflow name as 4th parameter of `Event` constructor in favor of the workflow itself.
|
||||
|
@ -1,6 +1,11 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* add a `workflow_metadata` function
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
|
@ -37,6 +37,7 @@ class WorkflowExtension extends AbstractExtension
|
||||
new TwigFunction('workflow_transitions', array($this, 'getEnabledTransitions')),
|
||||
new TwigFunction('workflow_has_marked_place', array($this, 'hasMarkedPlace')),
|
||||
new TwigFunction('workflow_marked_places', array($this, 'getMarkedPlaces')),
|
||||
new TwigFunction('workflow_metadata', array($this, 'getMetadata')),
|
||||
);
|
||||
}
|
||||
|
||||
@ -101,6 +102,24 @@ class WorkflowExtension extends AbstractExtension
|
||||
return $places;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata for a specific subject.
|
||||
*
|
||||
* @param object $subject A subject
|
||||
* @param null|string|Transition $metadataSubject Use null to get workflow metadata
|
||||
* Use a string (the place name) to get place metadata
|
||||
* Use a Transition instance to get transition metadata
|
||||
*/
|
||||
public function getMetadata($subject, string $key, $metadataSubject = null, string $name = null): ?string
|
||||
{
|
||||
return $this
|
||||
->workflowRegistry
|
||||
->get($subject, $name)
|
||||
->getMetadataStore()
|
||||
->getMetadata($key, $metadataSubject)
|
||||
;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'workflow';
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Bridge\Twig\Tests\Extension;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bridge\Twig\Extension\WorkflowExtension;
|
||||
use Symfony\Component\Workflow\Definition;
|
||||
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
use Symfony\Component\Workflow\SupportStrategy\ClassInstanceSupportStrategy;
|
||||
use Symfony\Component\Workflow\SupportStrategy\InstanceOfSupportStrategy;
|
||||
@ -23,6 +24,7 @@ use Symfony\Component\Workflow\Workflow;
|
||||
class WorkflowExtensionTest extends TestCase
|
||||
{
|
||||
private $extension;
|
||||
private $t1;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
@ -32,10 +34,21 @@ class WorkflowExtensionTest extends TestCase
|
||||
|
||||
$places = array('ordered', 'waiting_for_payment', 'processed');
|
||||
$transitions = array(
|
||||
new Transition('t1', 'ordered', 'waiting_for_payment'),
|
||||
$this->t1 = new Transition('t1', 'ordered', 'waiting_for_payment'),
|
||||
new Transition('t2', 'waiting_for_payment', 'processed'),
|
||||
);
|
||||
$definition = new Definition($places, $transitions);
|
||||
|
||||
$metadataStore = null;
|
||||
if (class_exists(InMemoryMetadataStore::class)) {
|
||||
$transitionsMetadata = new \SplObjectStorage();
|
||||
$transitionsMetadata->attach($this->t1, array('title' => 't1 title'));
|
||||
$metadataStore = new InMemoryMetadataStore(
|
||||
array('title' => 'workflow title'),
|
||||
array('orderer' => array('title' => 'ordered title')),
|
||||
$transitionsMetadata
|
||||
);
|
||||
}
|
||||
$definition = new Definition($places, $transitions, null, $metadataStore);
|
||||
$workflow = new Workflow($definition);
|
||||
|
||||
$registry = new Registry();
|
||||
@ -88,4 +101,19 @@ class WorkflowExtensionTest extends TestCase
|
||||
$this->assertSame(array('ordered', 'waiting_for_payment'), $this->extension->getMarkedPlaces($subject));
|
||||
$this->assertSame($subject->marking, $this->extension->getMarkedPlaces($subject, false));
|
||||
}
|
||||
|
||||
public function testGetMetadata()
|
||||
{
|
||||
if (!class_exists(InMemoryMetadataStore::class)) {
|
||||
$this->markTestSkipped('This test requires symfony/workflow:4.1.');
|
||||
}
|
||||
$subject = new \stdClass();
|
||||
$subject->marking = array();
|
||||
|
||||
$this->assertSame('workflow title', $this->extension->getMetadata($subject, 'title'));
|
||||
$this->assertSame('ordered title', $this->extension->getMetadata($subject, 'title', 'orderer'));
|
||||
$this->assertSame('t1 title', $this->extension->getMetadata($subject, 'title', $this->t1));
|
||||
$this->assertNull($this->extension->getMetadata($subject, 'not found'));
|
||||
$this->assertNull($this->extension->getMetadata($subject, 'not found', $this->t1));
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ use Symfony\Component\WebLink\HttpHeaderSerializer;
|
||||
* FrameworkExtension configuration structure.
|
||||
*
|
||||
* @author Jeremy Mikola <jmikola@gmail.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
class Configuration implements ConfigurationInterface
|
||||
{
|
||||
@ -292,23 +293,61 @@ class Configuration implements ConfigurationInterface
|
||||
->defaultNull()
|
||||
->end()
|
||||
->arrayNode('places')
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function ($places) {
|
||||
// It's an indexed array of shape ['place1', 'place2']
|
||||
if (isset($places[0]) && is_string($places[0])) {
|
||||
return array_map(function (string $place) {
|
||||
return array('name' => $place);
|
||||
}, $places);
|
||||
}
|
||||
|
||||
// It's an indexed array, we let the validation occur
|
||||
if (isset($places[0]) && is_array($places[0])) {
|
||||
return $places;
|
||||
}
|
||||
|
||||
foreach ($places as $name => $place) {
|
||||
if (is_array($place) && array_key_exists('name', $place)) {
|
||||
continue;
|
||||
}
|
||||
$place['name'] = $name;
|
||||
$places[$name] = $place;
|
||||
}
|
||||
|
||||
return array_values($places);
|
||||
})
|
||||
->end()
|
||||
->isRequired()
|
||||
->requiresAtLeastOneElement()
|
||||
->prototype('scalar')
|
||||
->cannotBeEmpty()
|
||||
->prototype('array')
|
||||
->children()
|
||||
->scalarNode('name')
|
||||
->isRequired()
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->arrayNode('metadata')
|
||||
->normalizeKeys(false)
|
||||
->defaultValue(array())
|
||||
->example(array('color' => 'blue', 'description' => 'Workflow to manage article.'))
|
||||
->prototype('variable')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('transitions')
|
||||
->beforeNormalization()
|
||||
->always()
|
||||
->then(function ($transitions) {
|
||||
// It's an indexed array, we let the validation occurs
|
||||
if (isset($transitions[0])) {
|
||||
// It's an indexed array, we let the validation occur
|
||||
if (isset($transitions[0]) && is_array($transitions[0])) {
|
||||
return $transitions;
|
||||
}
|
||||
|
||||
foreach ($transitions as $name => $transition) {
|
||||
if (array_key_exists('name', $transition)) {
|
||||
if (is_array($transition) && array_key_exists('name', $transition)) {
|
||||
continue;
|
||||
}
|
||||
$transition['name'] = $name;
|
||||
@ -351,9 +390,23 @@ class Configuration implements ConfigurationInterface
|
||||
->cannotBeEmpty()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('metadata')
|
||||
->normalizeKeys(false)
|
||||
->defaultValue(array())
|
||||
->example(array('color' => 'blue', 'description' => 'Workflow to manage article.'))
|
||||
->prototype('variable')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->arrayNode('metadata')
|
||||
->normalizeKeys(false)
|
||||
->defaultValue(array())
|
||||
->example(array('color' => 'blue', 'description' => 'Workflow to manage article.'))
|
||||
->prototype('variable')
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->validate()
|
||||
->ifTrue(function ($v) {
|
||||
|
@ -466,32 +466,68 @@ class FrameworkExtension extends Extension
|
||||
foreach ($config['workflows'] as $name => $workflow) {
|
||||
$type = $workflow['type'];
|
||||
|
||||
// Process Metadata (workflow + places (transition is done in the "create transition" block))
|
||||
$metadataStoreDefinition = new Definition(Workflow\Metadata\InMemoryMetadataStore::class, array(null, null, null));
|
||||
if ($workflow['metadata']) {
|
||||
$metadataStoreDefinition->replaceArgument(0, $workflow['metadata']);
|
||||
}
|
||||
$placesMetadata = array();
|
||||
foreach ($workflow['places'] as $place) {
|
||||
if ($place['metadata']) {
|
||||
$placesMetadata[$place['name']] = $place['metadata'];
|
||||
}
|
||||
}
|
||||
if ($placesMetadata) {
|
||||
$metadataStoreDefinition->replaceArgument(1, $placesMetadata);
|
||||
}
|
||||
|
||||
// Create transitions
|
||||
$transitions = array();
|
||||
$transitionsMetadataDefinition = new Definition(\SplObjectStorage::class);
|
||||
foreach ($workflow['transitions'] as $transition) {
|
||||
if ('workflow' === $type) {
|
||||
$transitions[] = new Definition(Workflow\Transition::class, array($transition['name'], $transition['from'], $transition['to']));
|
||||
$transitionDefinition = new Definition(Workflow\Transition::class, array($transition['name'], $transition['from'], $transition['to']));
|
||||
$transitions[] = $transitionDefinition;
|
||||
if ($transition['metadata']) {
|
||||
$transitionsMetadataDefinition->addMethodCall('attach', array(
|
||||
$transitionDefinition,
|
||||
$transition['metadata'],
|
||||
));
|
||||
}
|
||||
} elseif ('state_machine' === $type) {
|
||||
foreach ($transition['from'] as $from) {
|
||||
foreach ($transition['to'] as $to) {
|
||||
$transitions[] = new Definition(Workflow\Transition::class, array($transition['name'], $from, $to));
|
||||
$transitionDefinition = new Definition(Workflow\Transition::class, array($transition['name'], $from, $to));
|
||||
$transitions[] = $transitionDefinition;
|
||||
if ($transition['metadata']) {
|
||||
$transitionsMetadataDefinition->addMethodCall('attach', array(
|
||||
$transitionDefinition,
|
||||
$transition['metadata'],
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$metadataStoreDefinition->replaceArgument(2, $transitionsMetadataDefinition);
|
||||
|
||||
// Create places
|
||||
$places = array_map(function (array $place) {
|
||||
return $place['name'];
|
||||
}, $workflow['places']);
|
||||
|
||||
// Create a Definition
|
||||
$definitionDefinition = new Definition(Workflow\Definition::class);
|
||||
$definitionDefinition->setPublic(false);
|
||||
$definitionDefinition->addArgument($workflow['places']);
|
||||
$definitionDefinition->addArgument($places);
|
||||
$definitionDefinition->addArgument($transitions);
|
||||
$definitionDefinition->addArgument($workflow['initial_place'] ?? null);
|
||||
$definitionDefinition->addArgument($metadataStoreDefinition);
|
||||
$definitionDefinition->addTag('workflow.definition', array(
|
||||
'name' => $name,
|
||||
'type' => $type,
|
||||
'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null,
|
||||
));
|
||||
if (isset($workflow['initial_place'])) {
|
||||
$definitionDefinition->addArgument($workflow['initial_place']);
|
||||
}
|
||||
|
||||
// Create MarkingStore
|
||||
if (isset($workflow['marking_store']['type'])) {
|
||||
|
@ -273,8 +273,9 @@
|
||||
<xsd:sequence>
|
||||
<xsd:element name="marking-store" type="marking_store" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="support" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="place" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="place" type="place" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="transition" type="transition" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xsd:element name="metadata" type="metadata" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="workflow_type" />
|
||||
@ -302,10 +303,24 @@
|
||||
<xsd:sequence>
|
||||
<xsd:element name="from" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xsd:element name="to" type="xsd:string" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xsd:element name="metadata" type="metadata" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="place" mixed="true">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="metadata" type="metadata" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="metadata">
|
||||
<xsd:sequence>
|
||||
<xsd:any minOccurs="0" processContents="lax"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:simpleType name="workflow_type">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="state_machine" />
|
||||
|
@ -48,18 +48,29 @@ $container->loadFromExtension('framework', array(
|
||||
FrameworkExtensionTest::class,
|
||||
),
|
||||
'initial_place' => 'start',
|
||||
'metadata' => array(
|
||||
'title' => 'workflow title',
|
||||
),
|
||||
'places' => array(
|
||||
'start',
|
||||
'coding',
|
||||
'travis',
|
||||
'review',
|
||||
'merged',
|
||||
'closed',
|
||||
'start_name_not_used' => array(
|
||||
'name' => 'start',
|
||||
'metadata' => array(
|
||||
'title' => 'place start title',
|
||||
),
|
||||
),
|
||||
'coding' => null,
|
||||
'travis' => null,
|
||||
'review' => null,
|
||||
'merged' => null,
|
||||
'closed' => null,
|
||||
),
|
||||
'transitions' => array(
|
||||
'submit' => array(
|
||||
'from' => 'start',
|
||||
'to' => 'travis',
|
||||
'metadata' => array(
|
||||
'title' => 'transition submit title',
|
||||
),
|
||||
),
|
||||
'update' => array(
|
||||
'from' => array('coding', 'travis', 'review'),
|
||||
@ -96,8 +107,8 @@ $container->loadFromExtension('framework', array(
|
||||
FrameworkExtensionTest::class,
|
||||
),
|
||||
'places' => array(
|
||||
'first',
|
||||
'last',
|
||||
array('name' => 'first'),
|
||||
array('name' => 'last'),
|
||||
),
|
||||
'transitions' => array(
|
||||
'go' => array(
|
||||
|
@ -13,8 +13,8 @@
|
||||
<framework:argument>a</framework:argument>
|
||||
</framework:marking-store>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>first</framework:place>
|
||||
<framework:place>last</framework:place>
|
||||
<framework:place name="first" />
|
||||
<framework:place name="last" />
|
||||
<framework:transition name="foobar">
|
||||
<framework:from>a</framework:from>
|
||||
<framework:to>a</framework:to>
|
||||
|
@ -13,12 +13,12 @@
|
||||
<framework:argument>a</framework:argument>
|
||||
</framework:marking-store>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>draft</framework:place>
|
||||
<framework:place>wait_for_journalist</framework:place>
|
||||
<framework:place>approved_by_journalist</framework:place>
|
||||
<framework:place>wait_for_spellchecker</framework:place>
|
||||
<framework:place>approved_by_spellchecker</framework:place>
|
||||
<framework:place>published</framework:place>
|
||||
<framework:place name="draft" />
|
||||
<framework:place name="wait_for_journalist" />
|
||||
<framework:place name="approved_by_journalist" />
|
||||
<framework:place name="wait_for_spellchecker" />
|
||||
<framework:place name="approved_by_spellchecker" />
|
||||
<framework:place name="published" />
|
||||
<framework:transition name="request_review">
|
||||
<framework:from>draft</framework:from>
|
||||
<framework:to>wait_for_journalist</framework:to>
|
||||
|
@ -10,8 +10,8 @@
|
||||
<framework:workflow name="my_workflow" support-strategy="foobar">
|
||||
<framework:marking-store type="multiple_state"/>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>first</framework:place>
|
||||
<framework:place>last</framework:place>
|
||||
<framework:place name="first" />
|
||||
<framework:place name="last" />
|
||||
<framework:transition name="foobar">
|
||||
<framework:from>a</framework:from>
|
||||
<framework:to>a</framework:to>
|
||||
|
@ -10,8 +10,8 @@
|
||||
<framework:workflow name="my_workflow">
|
||||
<framework:marking-store type="multiple_state" service="workflow_service" />
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>first</framework:place>
|
||||
<framework:place>last</framework:place>
|
||||
<framework:place name="first" />
|
||||
<framework:place name="last" />
|
||||
<framework:transition name="foobar">
|
||||
<framework:from>a</framework:from>
|
||||
<framework:to>a</framework:to>
|
||||
|
@ -9,8 +9,8 @@
|
||||
<framework:config>
|
||||
<framework:workflow name="my_workflow">
|
||||
<framework:marking-store type="multiple_state"/>
|
||||
<framework:place>first</framework:place>
|
||||
<framework:place>last</framework:place>
|
||||
<framework:place name="first" />
|
||||
<framework:place name="last" />
|
||||
<framework:transition name="foobar">
|
||||
<framework:from>a</framework:from>
|
||||
<framework:to>a</framework:to>
|
||||
|
@ -13,12 +13,12 @@
|
||||
<framework:argument>a</framework:argument>
|
||||
</framework:marking-store>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>draft</framework:place>
|
||||
<framework:place>wait_for_journalist</framework:place>
|
||||
<framework:place>approved_by_journalist</framework:place>
|
||||
<framework:place>wait_for_spellchecker</framework:place>
|
||||
<framework:place>approved_by_spellchecker</framework:place>
|
||||
<framework:place>published</framework:place>
|
||||
<framework:place name="draft"></framework:place>
|
||||
<framework:place name="wait_for_journalist"></framework:place>
|
||||
<framework:place name="approved_by_journalist"></framework:place>
|
||||
<framework:place name="wait_for_spellchecker"></framework:place>
|
||||
<framework:place name="approved_by_spellchecker"></framework:place>
|
||||
<framework:place name="published"></framework:place>
|
||||
<framework:transition name="request_review">
|
||||
<framework:from>draft</framework:from>
|
||||
<framework:to>wait_for_journalist</framework:to>
|
||||
@ -42,15 +42,22 @@
|
||||
<framework:workflow name="pull_request" initial-place="start">
|
||||
<framework:marking-store type="single_state"/>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<framework:place>start</framework:place>
|
||||
<framework:place>coding</framework:place>
|
||||
<framework:place>travis</framework:place>
|
||||
<framework:place>review</framework:place>
|
||||
<framework:place>merged</framework:place>
|
||||
<framework:place>closed</framework:place>
|
||||
<framework:place name="start">
|
||||
<framework:metadata>
|
||||
<framework:title>place start title</framework:title>
|
||||
</framework:metadata>
|
||||
</framework:place>
|
||||
<framework:place name="coding"></framework:place>
|
||||
<framework:place name="travis"></framework:place>
|
||||
<framework:place name="review"></framework:place>
|
||||
<framework:place name="merged"></framework:place>
|
||||
<framework:place name="closed"></framework:place>
|
||||
<framework:transition name="submit">
|
||||
<framework:from>start</framework:from>
|
||||
<framework:to>travis</framework:to>
|
||||
<framework:metadata>
|
||||
<framework:title>transition submit title</framework:title>
|
||||
</framework:metadata>
|
||||
</framework:transition>
|
||||
<framework:transition name="update">
|
||||
<framework:from>coding</framework:from>
|
||||
@ -78,11 +85,15 @@
|
||||
<framework:from>closed</framework:from>
|
||||
<framework:to>review</framework:to>
|
||||
</framework:transition>
|
||||
<framework:metadata>
|
||||
<framework:title>workflow title</framework:title>
|
||||
</framework:metadata>
|
||||
</framework:workflow>
|
||||
|
||||
<framework:workflow name="service_marking_store_workflow" type="workflow">
|
||||
<framework:marking-store service="workflow_service"/>
|
||||
<framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support>
|
||||
<!-- Simple format -->
|
||||
<framework:place>first</framework:place>
|
||||
<framework:place>last</framework:place>
|
||||
<framework:transition name="go">
|
||||
|
@ -8,6 +8,7 @@ framework:
|
||||
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
|
||||
initial_place: draft
|
||||
places:
|
||||
# simple format
|
||||
- draft
|
||||
- wait_for_journalist
|
||||
- approved_by_journalist
|
||||
@ -33,17 +34,24 @@ framework:
|
||||
supports:
|
||||
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
|
||||
initial_place: start
|
||||
metadata:
|
||||
title: workflow title
|
||||
places:
|
||||
- start
|
||||
- coding
|
||||
- travis
|
||||
- review
|
||||
- merged
|
||||
- closed
|
||||
start_name_not_used:
|
||||
name: start
|
||||
metadata:
|
||||
title: place start title
|
||||
coding: ~
|
||||
travis: ~
|
||||
review: ~
|
||||
merged: ~
|
||||
closed: ~
|
||||
transitions:
|
||||
submit:
|
||||
from: start
|
||||
to: travis
|
||||
metadata:
|
||||
title: transition submit title
|
||||
update:
|
||||
from: [coding, travis, review]
|
||||
to: travis
|
||||
@ -69,8 +77,8 @@ framework:
|
||||
supports:
|
||||
- Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
|
||||
places:
|
||||
- first
|
||||
- last
|
||||
- { name: first }
|
||||
- { name: last }
|
||||
transitions:
|
||||
go:
|
||||
from:
|
||||
|
@ -43,7 +43,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
|
||||
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
|
||||
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
use Symfony\Component\Workflow;
|
||||
|
||||
abstract class FrameworkExtensionTest extends TestCase
|
||||
{
|
||||
@ -209,12 +209,12 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
'Places are passed to the workflow definition'
|
||||
);
|
||||
$this->assertSame(array('workflow.definition' => array(array('name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state'))), $workflowDefinition->getTags());
|
||||
$this->assertCount(4, $workflowDefinition->getArgument(1));
|
||||
$this->assertSame('draft', $workflowDefinition->getArgument(2));
|
||||
|
||||
$this->assertTrue($container->hasDefinition('state_machine.pull_request'), 'State machine is registered as a service');
|
||||
$this->assertSame('state_machine.abstract', $container->getDefinition('state_machine.pull_request')->getParent());
|
||||
$this->assertTrue($container->hasDefinition('state_machine.pull_request.definition'), 'State machine definition is registered as a service');
|
||||
$this->assertCount(4, $workflowDefinition->getArgument(1));
|
||||
$this->assertSame('draft', $workflowDefinition->getArgument(2));
|
||||
|
||||
$stateMachineDefinition = $container->getDefinition('state_machine.pull_request.definition');
|
||||
|
||||
@ -234,6 +234,28 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
$this->assertCount(9, $stateMachineDefinition->getArgument(1));
|
||||
$this->assertSame('start', $stateMachineDefinition->getArgument(2));
|
||||
|
||||
$metadataStoreDefinition = $stateMachineDefinition->getArgument(3);
|
||||
$this->assertInstanceOf(Definition::class, $metadataStoreDefinition);
|
||||
$this->assertSame(Workflow\Metadata\InMemoryMetadataStore::class, $metadataStoreDefinition->getClass());
|
||||
|
||||
$workflowMetadata = $metadataStoreDefinition->getArgument(0);
|
||||
$this->assertSame(array('title' => 'workflow title'), $workflowMetadata);
|
||||
|
||||
$placesMetadata = $metadataStoreDefinition->getArgument(1);
|
||||
$this->assertArrayHasKey('start', $placesMetadata);
|
||||
$this->assertSame(array('title' => 'place start title'), $placesMetadata['start']);
|
||||
|
||||
$transitionsMetadata = $metadataStoreDefinition->getArgument(2);
|
||||
$this->assertSame(\SplObjectStorage::class, $transitionsMetadata->getClass());
|
||||
$transitionsMetadataCall = $transitionsMetadata->getMethodCalls()[0];
|
||||
$this->assertSame('attach', $transitionsMetadataCall[0]);
|
||||
$params = $transitionsMetadataCall[1];
|
||||
$this->assertCount(2, $params);
|
||||
$this->assertInstanceOf(Definition::class, $params[0]);
|
||||
$this->assertSame(Workflow\Transition::class, $params[0]->getClass());
|
||||
$this->assertSame(array('submit', 'start', 'travis'), $params[0]->getArguments());
|
||||
$this->assertSame(array('title' => 'transition submit title'), $params[1]);
|
||||
|
||||
$serviceMarkingStoreWorkflowDefinition = $container->getDefinition('workflow.service_marking_store_workflow');
|
||||
/** @var Reference $markingStoreRef */
|
||||
$markingStoreRef = $serviceMarkingStoreWorkflowDefinition->getArgument(1);
|
||||
@ -308,7 +330,7 @@ abstract class FrameworkExtensionTest extends TestCase
|
||||
{
|
||||
$container = $this->createContainerFromFile('workflows_enabled');
|
||||
|
||||
$this->assertTrue($container->has(Registry::class));
|
||||
$this->assertTrue($container->has(Workflow\Registry::class));
|
||||
$this->assertTrue($container->hasDefinition('console.command.workflow_dump'));
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ CHANGELOG
|
||||
* Deprecated the class `ClassInstanceSupportStrategy` in favor of the class `InstanceOfSupportStrategy`.
|
||||
* Added TransitionBlockers as a way to pass around reasons why exactly
|
||||
transitions can't be made.
|
||||
* Added a `MetadataStore`.
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
@ -12,6 +12,8 @@
|
||||
namespace Symfony\Component\Workflow;
|
||||
|
||||
use Symfony\Component\Workflow\Exception\LogicException;
|
||||
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
|
||||
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
@ -23,13 +25,14 @@ final class Definition
|
||||
private $places = array();
|
||||
private $transitions = array();
|
||||
private $initialPlace;
|
||||
private $metadataStore;
|
||||
|
||||
/**
|
||||
* @param string[] $places
|
||||
* @param Transition[] $transitions
|
||||
* @param string|null $initialPlace
|
||||
*/
|
||||
public function __construct(array $places, array $transitions, string $initialPlace = null)
|
||||
public function __construct(array $places, array $transitions, string $initialPlace = null, MetadataStoreInterface $metadataStore = null)
|
||||
{
|
||||
foreach ($places as $place) {
|
||||
$this->addPlace($place);
|
||||
@ -40,6 +43,8 @@ final class Definition
|
||||
}
|
||||
|
||||
$this->setInitialPlace($initialPlace);
|
||||
|
||||
$this->metadataStore = $metadataStore ?: new InMemoryMetadataStore();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,6 +71,11 @@ final class Definition
|
||||
return $this->transitions;
|
||||
}
|
||||
|
||||
public function getMetadataStore(): MetadataStoreInterface
|
||||
{
|
||||
return $this->metadataStore;
|
||||
}
|
||||
|
||||
private function setInitialPlace(string $place = null)
|
||||
{
|
||||
if (null === $place) {
|
||||
|
@ -12,8 +12,10 @@
|
||||
namespace Symfony\Component\Workflow\Event;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event as BaseEvent;
|
||||
use Symfony\Component\Workflow\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Workflow\Marking;
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
use Symfony\Component\Workflow\WorkflowInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
@ -24,20 +26,28 @@ class Event extends BaseEvent
|
||||
private $subject;
|
||||
private $marking;
|
||||
private $transition;
|
||||
private $workflow;
|
||||
private $workflowName;
|
||||
|
||||
/**
|
||||
* @param object $subject
|
||||
* @param Marking $marking
|
||||
* @param Transition $transition
|
||||
* @param string $workflowName
|
||||
* @param Workflow $workflow
|
||||
*/
|
||||
public function __construct($subject, Marking $marking, Transition $transition, string $workflowName = 'unnamed')
|
||||
public function __construct($subject, Marking $marking, Transition $transition, $workflow = null)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->marking = $marking;
|
||||
$this->transition = $transition;
|
||||
$this->workflowName = $workflowName;
|
||||
if (is_string($workflow)) {
|
||||
@trigger_error(sprintf('Passing a string as 4th parameter of "%s" is deprecated since Symfony 4.1. Pass a %s instance instead.', __METHOD__, WorkflowInterface::class), E_USER_DEPRECATED);
|
||||
$this->workflowName = $workflow;
|
||||
} elseif ($workflow instanceof WorkflowInterface) {
|
||||
$this->workflow = $workflow;
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf('The 4th parameter of "%s" should be a "%s" instance instead.', __METHOD__, WorkflowInterface::class));
|
||||
}
|
||||
}
|
||||
|
||||
public function getMarking()
|
||||
@ -55,8 +65,38 @@ class Event extends BaseEvent
|
||||
return $this->transition;
|
||||
}
|
||||
|
||||
public function getWorkflow(): WorkflowInterface
|
||||
{
|
||||
// BC layer
|
||||
if (!$this->workflow instanceof WorkflowInterface) {
|
||||
throw new \RuntimeException(sprintf('The 4th parameter of "%s"::__construct() should be a "%s" instance.', __CLASS__, WorkflowInterface::class));
|
||||
}
|
||||
|
||||
return $this->workflow;
|
||||
}
|
||||
|
||||
public function getWorkflowName()
|
||||
{
|
||||
return $this->workflowName;
|
||||
// BC layer
|
||||
if ($this->workflowName) {
|
||||
return $this->workflowName;
|
||||
}
|
||||
|
||||
// BC layer
|
||||
if (!$this->workflow instanceof WorkflowInterface) {
|
||||
throw new \RuntimeException(sprintf('The 4th parameter of "%s"::__construct() should be a "%s" instance.', __CLASS__, WorkflowInterface::class));
|
||||
}
|
||||
|
||||
return $this->workflow->getName();
|
||||
}
|
||||
|
||||
public function getMetadata(string $key, $subject)
|
||||
{
|
||||
// BC layer
|
||||
if (!$this->workflow instanceof WorkflowInterface) {
|
||||
throw new \RuntimeException(sprintf('The 4th parameter of "%s"::__construct() should be a "%s" instance.', __CLASS__, WorkflowInterface::class));
|
||||
}
|
||||
|
||||
return $this->workflow->getMetadataStore()->getMetadata($key, $subject);
|
||||
}
|
||||
}
|
||||
|
48
src/Symfony/Component/Workflow/Metadata/GetMetadataTrait.php
Normal file
48
src/Symfony/Component/Workflow/Metadata/GetMetadataTrait.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?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\Metadata;
|
||||
|
||||
use Symfony\Component\Workflow\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
|
||||
/**
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
trait GetMetadataTrait
|
||||
{
|
||||
public function getMetadata(string $key, $subject = null)
|
||||
{
|
||||
if (null === $subject) {
|
||||
return $this->getWorkflowMetadata()[$key] ?? null;
|
||||
}
|
||||
|
||||
if (\is_string($subject)) {
|
||||
$metadataBag = $this->getPlaceMetadata($subject);
|
||||
if (!$metadataBag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $metadataBag[$key] ?? null;
|
||||
}
|
||||
|
||||
if ($subject instanceof Transition) {
|
||||
$metadataBag = $this->getTransitionMetadata($subject);
|
||||
if (!$metadataBag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $metadataBag[$key] ?? null;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Could not find a MetadataBag for the subject of type "%s".', is_object($subject) ? get_class($subject) : gettype($subject)));
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<?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\Metadata;
|
||||
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
|
||||
/**
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
final class InMemoryMetadataStore implements MetadataStoreInterface
|
||||
{
|
||||
use GetMetadataTrait;
|
||||
|
||||
private $workflowMetadata;
|
||||
private $placesMetadata;
|
||||
private $transitionsMetadata;
|
||||
|
||||
public function __construct($workflowMetadata = array(), array $placesMetadata = array(), \SplObjectStorage $transitionsMetadata = null)
|
||||
{
|
||||
$this->workflowMetadata = $workflowMetadata;
|
||||
$this->placesMetadata = $placesMetadata;
|
||||
$this->transitionsMetadata = $transitionsMetadata ?: new \SplObjectStorage();
|
||||
}
|
||||
|
||||
public function getWorkflowMetadata(): array
|
||||
{
|
||||
return $this->workflowMetadata;
|
||||
}
|
||||
|
||||
public function getPlaceMetadata(string $place): array
|
||||
{
|
||||
return $this->placesMetadata[$place] ?? array();
|
||||
}
|
||||
|
||||
public function getTransitionMetadata(Transition $transition): array
|
||||
{
|
||||
return $this->transitionsMetadata[$transition] ?? array();
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?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\Metadata;
|
||||
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
|
||||
/**
|
||||
* MetadataStoreInterface is able to fetch metadata for a specific workflow.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
interface MetadataStoreInterface
|
||||
{
|
||||
public function getWorkflowMetadata(): array;
|
||||
|
||||
public function getPlaceMetadata(string $place): array;
|
||||
|
||||
public function getTransitionMetadata(Transition $transition): array;
|
||||
|
||||
/**
|
||||
* Returns the metadata for a specific subject.
|
||||
*
|
||||
* This is a proxy method.
|
||||
*
|
||||
* @param null|string|Transition $subject Use null to get workflow metadata
|
||||
* Use a string (the place name) to get place metadata
|
||||
* Use a Transition instance to get transition metadata
|
||||
*/
|
||||
public function getMetadata(string $key, $subject = null);
|
||||
}
|
@ -14,6 +14,7 @@ use Symfony\Component\Workflow\EventListener\GuardListener;
|
||||
use Symfony\Component\Workflow\Event\GuardEvent;
|
||||
use Symfony\Component\Workflow\Marking;
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
use Symfony\Component\Workflow\WorkflowInterface;
|
||||
|
||||
class GuardListenerTest extends TestCase
|
||||
{
|
||||
@ -102,7 +103,9 @@ class GuardListenerTest extends TestCase
|
||||
$subject->marking = new Marking();
|
||||
$transition = new Transition('name', 'from', 'to');
|
||||
|
||||
return new GuardEvent($subject, $subject->marking, $transition);
|
||||
$workflow = $this->getMockBuilder(WorkflowInterface::class)->getMock();
|
||||
|
||||
return new GuardEvent($subject, $subject->marking, $transition, $workflow);
|
||||
}
|
||||
|
||||
private function configureAuthenticationChecker($isUsed, $granted = true)
|
||||
|
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Workflow\Tests\Metadata;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
|
||||
use Symfony\Component\Workflow\Transition;
|
||||
|
||||
/**
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
class InMemoryMetadataStoreTest extends TestCase
|
||||
{
|
||||
private $store;
|
||||
private $transition;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$workflowMetadata = array(
|
||||
'title' => 'workflow title',
|
||||
);
|
||||
$placesMetadata = array(
|
||||
'place_a' => array(
|
||||
'title' => 'place_a title',
|
||||
),
|
||||
);
|
||||
$transitionsMetadata = new \SplObjectStorage();
|
||||
$this->transition = new Transition('transition_1', array(), array());
|
||||
$transitionsMetadata[$this->transition] = array(
|
||||
'title' => 'transition_1 title',
|
||||
);
|
||||
|
||||
$this->store = new InMemoryMetadataStore($workflowMetadata, $placesMetadata, $transitionsMetadata);
|
||||
}
|
||||
|
||||
public function testGetWorkflowMetadata()
|
||||
{
|
||||
$metadataBag = $this->store->getWorkflowMetadata();
|
||||
$this->assertSame('workflow title', $metadataBag['title']);
|
||||
}
|
||||
|
||||
public function testGetUnexistingPlaceMetadata()
|
||||
{
|
||||
$metadataBag = $this->store->getPlaceMetadata('place_b');
|
||||
$this->assertSame(array(), $metadataBag);
|
||||
}
|
||||
|
||||
public function testGetExistingPlaceMetadata()
|
||||
{
|
||||
$metadataBag = $this->store->getPlaceMetadata('place_a');
|
||||
$this->assertSame('place_a title', $metadataBag['title']);
|
||||
}
|
||||
|
||||
public function testGetUnexistingTransitionMetadata()
|
||||
{
|
||||
$metadataBag = $this->store->getTransitionMetadata(new Transition('transition_2', array(), array()));
|
||||
$this->assertSame(array(), $metadataBag);
|
||||
}
|
||||
|
||||
public function testGetExistingTransitionMetadata()
|
||||
{
|
||||
$metadataBag = $this->store->getTransitionMetadata($this->transition);
|
||||
$this->assertSame('transition_1 title', $metadataBag['title']);
|
||||
}
|
||||
|
||||
public function testGetMetadata()
|
||||
{
|
||||
$this->assertSame('workflow title', $this->store->getMetadata('title'));
|
||||
$this->assertNull($this->store->getMetadata('description'));
|
||||
$this->assertSame('place_a title', $this->store->getMetadata('title', 'place_a'));
|
||||
$this->assertNull($this->store->getMetadata('description', 'place_a'));
|
||||
$this->assertNull($this->store->getMetadata('description', 'place_b'));
|
||||
$this->assertSame('transition_1 title', $this->store->getMetadata('title', $this->transition));
|
||||
$this->assertNull($this->store->getMetadata('description', $this->transition));
|
||||
$this->assertNull($this->store->getMetadata('description', new Transition('transition_2', array(), array())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Workflow\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage Could not find a MetadataBag for the subject of type "boolean".
|
||||
*/
|
||||
public function testGetMetadataWithUnknownType()
|
||||
{
|
||||
$this->store->getMetadata('title', true);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ use Symfony\Component\Workflow\Exception\NotEnabledTransitionException;
|
||||
use Symfony\Component\Workflow\Exception\UndefinedTransitionException;
|
||||
use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;
|
||||
use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore;
|
||||
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
@ -219,6 +220,14 @@ class Workflow implements WorkflowInterface
|
||||
return $this->markingStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetadataStore(): MetadataStoreInterface
|
||||
{
|
||||
return $this->definition->getMetadataStore();
|
||||
}
|
||||
|
||||
private function buildTransitionBlockerListForTransition($subject, Marking $marking, Transition $transition)
|
||||
{
|
||||
foreach ($transition->getFroms() as $place) {
|
||||
@ -248,7 +257,7 @@ class Workflow implements WorkflowInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
$event = new GuardEvent($subject, $marking, $transition, $this->name);
|
||||
$event = new GuardEvent($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.guard', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.guard', $this->name), $event);
|
||||
@ -262,7 +271,7 @@ class Workflow implements WorkflowInterface
|
||||
$places = $transition->getFroms();
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$event = new Event($subject, $marking, $transition, $this->name);
|
||||
$event = new Event($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.leave', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.leave', $this->name), $event);
|
||||
@ -283,7 +292,7 @@ class Workflow implements WorkflowInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$event = new Event($subject, $marking, $transition, $this->name);
|
||||
$event = new Event($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.transition', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.transition', $this->name), $event);
|
||||
@ -295,7 +304,7 @@ class Workflow implements WorkflowInterface
|
||||
$places = $transition->getTos();
|
||||
|
||||
if (null !== $this->dispatcher) {
|
||||
$event = new Event($subject, $marking, $transition, $this->name);
|
||||
$event = new Event($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.enter', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.enter', $this->name), $event);
|
||||
@ -316,7 +325,7 @@ class Workflow implements WorkflowInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$event = new Event($subject, $marking, $transition, $this->name);
|
||||
$event = new Event($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.entered', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.entered', $this->name), $event);
|
||||
@ -332,7 +341,7 @@ class Workflow implements WorkflowInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$event = new Event($subject, $marking, $transition, $this->name);
|
||||
$event = new Event($subject, $marking, $transition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.completed', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.completed', $this->name), $event);
|
||||
@ -345,7 +354,7 @@ class Workflow implements WorkflowInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$event = new Event($subject, $marking, $initialTransition, $this->name);
|
||||
$event = new Event($subject, $marking, $initialTransition, $this);
|
||||
|
||||
$this->dispatcher->dispatch('workflow.announce', $event);
|
||||
$this->dispatcher->dispatch(sprintf('workflow.%s.announce', $this->name), $event);
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Component\Workflow;
|
||||
|
||||
use Symfony\Component\Workflow\Exception\LogicException;
|
||||
use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;
|
||||
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
|
||||
|
||||
/**
|
||||
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
|
||||
@ -82,4 +83,6 @@ interface WorkflowInterface
|
||||
* @return MarkingStoreInterface
|
||||
*/
|
||||
public function getMarkingStore();
|
||||
|
||||
public function getMetadataStore(): MetadataStoreInterface;
|
||||
}
|
||||
|
Reference in New Issue
Block a user