Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

[Workflow] Make the Workflow support State Machines#19629

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
fabpot merged 2 commits intosymfony:masterfromNyholm:state-machine
Nov 7, 2016

Conversation

@Nyholm
Copy link
Member

@NyholmNyholm commentedAug 16, 2016
edited
Loading

QA
Branch?"master"
Bug fix?no
New feature?yes
BC breaks?yes, getEnabledTransistions does not return an assoc array.
Deprecations?no
Tests pass?yes
Fixed ticketsFixes#19605,Closes#19607
LicenseMIT
Doc PRsymfony/symfony-docs#6871

While researching for the docs of the component I've found that:

  • A Workflow is a subclass of a Petri net
  • A state machine is subclass of a Workflow
  • A state machine must not be in many places simultaneously.

This PR adds a new interface to the marking store that allow us to validate the transition to true if ANYinput (froms) place matches thetokens (marking). The default behavior is that ALL input places must match the tokens.

sgomez, lyrixx, and adam-paterson reacted with thumbs up emojirufinus reacted with heart emoji
// Marking must have ONE place
$preCondition =false;
foreach ($transition->getFroms()as$place) {
$preCondition =$preCondition ||$marking->has($place);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You can break as soon as you get atrue ?!

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Correct. I'll update

@stof
Copy link
Member

shouldn't state machines be implemented with transitions having a single starting place, instead of making a OR between places, which changes the meaning of the transition ?

I'm quite sure that your state machine doing a OR between starting places of a given transition should actually be implemented as several transitions with a single starting place each.
So for me, it is a 👎 for now.

@Nyholm
Copy link
MemberAuthor

Thank you for the feedback and for challenging the theory behind this. I appreciate that.

shouldn't state machines be implemented with transitions having a single starting place, instead of making a OR between places, which changes the meaning of the transition ?

(I assume that "starting place"="input place" and not "initial place")
Both yes and no. A state machine transition must have exactly one input place and output place, that is correct. But the name of the transition does not have to be unique (in theory, only in the current implementation). Which means that the following two examples are valid state machines.

// Example 1                             Could be considered the same as// a -> t1 -> b                           a -> t1 -> b//            ↑                                ↑// c -> t1 -> ⅃                                c
// Example 2// a -> t1 -> b//// c -> t1 -> d

The output state fort1 depends on the current state. SeeMoore machines.

Here is an example of the doors of an elevator (sourceWikipedia)
screen shot 2016-08-16 at 19 00 33

I'm quite sure that your state machine doing a OR between starting places of a given transition should actually be implemented as several transitions with a single starting place each.

Yes, it does a OR but as stated above that is okey. The alternative implementation of this is to rewriteDefinition::$transitions to support multiple transitions with the same name/id. That will be slower than the array that is currently used and it will require more configuration by the user,but it will not change the behavior.

RewritingDefinition::$transitions might be the only way to go if we also want to support Example 2.

@stof
Copy link
Member

Well, in your state machine, I consider that you have multiple transitions being labelled asopen, not a single transition handling many different changes in the graph.

IMO, requiring transition names to be unique is the actual issue in your case. Your proposal is actually changing the Workflow component to implement a weird thing. Your state machine above indeed has 6 transitions in your schema above

@Nyholm
Copy link
MemberAuthor

IMO, requiring transition names to be unique is the actual issue in your case. Your proposal is actually changing the Workflow component to implement a weird thing. Your state machine above indeed has 6 transitions in your schema above

You may be right. I have taken a shortcut here. We discussed non-unique transition names in#19605 as well. I'll see if I can find a better solution.

@ogizanagi
Copy link
Contributor

ogizanagi commentedAug 16, 2016
edited
Loading

@Nyholm
Copy link
MemberAuthor

I've update the PR now. I've made sure that the transition name can be non-unique. There is no shortcut, there is actually no decreased performance (I was wrong before) and the model is a better mapping of the state machine.

Please give it another review.

Note: This will be a BC break becauseWorkflow::getEnabledTransitions andDefinition::getTransitions will not return an assoc array anymore.

@lyrixx
Copy link
Member

Hello.

Unfortunately the transition name in a petri name should be unique.

Anyway, it's simpler to add a new attributeTransition::title to fix your issue.

@Nyholm
Copy link
MemberAuthor

Hey.

I can't find any documentations about petri nets that says that the transition name has to be unique. Can you provide a reference?

Anyway, it's simpler to add a new attribute Transition::title to fix your issue.

So the Transition::name will be an unique id and the Transition::title would be... used as an id when you doWorkflow::can andWorkflow::apply?

@lyrixx
Copy link
Member

lyrixx commentedAug 17, 2016
edited
Loading

no, withcan andapply you have to give the fullname. But you can use thetitle in the UI. everything is hidden for the end user after that. For example, the only line to update isthis one.

@Nyholm
Copy link
MemberAuthor

no, with can and apply you have to give the full name.

Then what is the point of adding atitle? Consider the elevator example above. I want to be able to do$workflow->apply($elevator, 'close'). I do not care if the elevator is in statusopened oropening.

If I still need the fullname I have to:

try {$workflow->apply($elevator,'close_if_opened');}catch ( .. ) {try {$workflow->apply($elevator,'close_if_opening');    }catch (...) { ... } }

Unfortunately the transition name in a petri name should be unique.

I can't find any documentations about petri nets that says that the transition name has to be unique. Can you provide a reference?

I have not found anything yet. Have you had any success?

@lyrixx
Copy link
Member

the point of adding a title is you hide the potential complexity of the workflow. You display to the end user a simple action like close. Then, because some transitions will not be available, the workflow will display only the close (close_if_opened) transition. and so you never had to hardcode close_if_opened.

Do you see what i'm trying to say ? If you can, I show you in with the example on my repo.

I have not found anything yet. Have you had any success?

Inhttps://en.wikipedia.org/wiki/Petri_net#Formal_definition_and_basic_terminology:

Definition 1. A net is a triple {\displaystyle N=(P,T,F)} N = (P, T, F) where:
P and T are disjoint finite sets of places and transitions, respectively.

And a set is a:

In mathematics, a set is a collection of distinct objects, considered as an object in its own right

@Nyholm
Copy link
MemberAuthor

I see what you mean by using a title. In your case it does make sense. But in my application I do not show the places/states to the end users. For example: I use a state machine to determent what emails to send. I do something like:

if ($workflow->can($object,'send_type1')) {// Do send$workflow->apply(...)}

"send_type1" could move the state froma,b andc to stated. That is why I do not want to dosend_type1_from_a,send_type1_from_b andsend_type1_from_c.


P and T are disjoint finite sets of places and transitions, respectively.

Yes, T is a set of disjoint objects. But it does not say anything about the name/title attributes of those objects that must be unique. In fact, the name of the object has nothing to do with the mathematical model.

@lyrixx
Copy link
Member

About your exemple, you can simply use $workflow->getEnabledTransitions to get the list of all available transition ?

Yes, T is a set of disjoint objects. But it does not say anything about the name/title attributes of those objects that must be unique. In fact, the name of the object has nothing to do with the mathematical model.

I guess I / You miss something because to me it's clear it should be unique.

@Nyholm
Copy link
MemberAuthor

Yeah, but Im not interested in getting a list what is enabled and then parse that list. I know the name of the action I want to do. I just want to check if I can do it or not.

Agreed. I think we intrepid the definition differently. For be it is clear that the transitions should be separate objects but the attributes of those objects do not have any restrictions.

Do you see any issues with the workflow net that two transitions share the same name?

@lyrixx
Copy link
Member

Do you see any issues with the workflow net that two transitions share the same name?

Right now, no. But I have a bad feeling about it. :/

@Nyholm
Copy link
MemberAuthor

Please elaborate. Im happy to challenge this PR.

This PR brings more flexibility. Wecould make sure to restrict us by forcing the transitions names to be unique whenever we add transition to theDefinition. Say we (in the future) create aTransitionNamesMustBeUniqueDefintion.

@lyrixx
Copy link
Member

(One week later) I still don't know what to think about this PR. It looks good to me but I'm still a bit afraid of potential side effect that I'm not able to see now.

@stof What do you think?

@stof
Copy link
Member

@lyrixx Well, transition names must be unique among transition sharing a starting place (otherwise asking to perform a transition would be ambiguous). But I don't see a need to make them unique in the whole graph (except maybe because of your feature about event being dispatched as you use the name in them, but the impact should be evaluated).

Regarding this PR, what I don't like is that it changes totally what a transition means in the workflow depending on some other thing. We should not have aUniqueTransitionInputInterface.

If we want to be able to enforce a state machine workflow, we should probably have a feature validating a workflow instance to enforce some rules. Here are a few ideas about what can be validated at this level:

  • enforcing uniqueness of the names of transitions starting at each node (always enabled IMO)
  • enforcing that transitions have a single starting place and a single end place (i.e. your workflow is a state machine)
    But we should not rely on an interface on the marking store to determine that. Enforcing a state machine workflow should not change anything to the marking store (except maybe adding a feature validating the fact that a marking store marks a single place initially, but even this PR does not do it)
ogizanagi and lyrixx reacted with thumbs up emoji

@fabpot
Copy link
Member

So, what do we do here?

@Nyholm
Copy link
MemberAuthor

I feel that we all want to support state machines. The question is HOW.

I like the idea by@stof to enforce some rules. What if we introduced a StateMachine class.

class PetriNet {// ...}class Workflowextends PetriNet {publicfunction__construct($definition, ...) {// Validate that the definition is a valid Workflow  }}class StateMachineextends PetriNet (Or WorkFlow) {publicfunction__construct($definition, ...) {// Validate that the definition is a valid StateMachine  }}

This would enforce the rules, remove the need forUniqueTransitionInputInterface and this inheritance makes a lot of sense if you considering the domain.

@lyrixx
Copy link
Member

Indeed I would be nice to support state machine out of the box. But I don't really like the current implementation, and I totally approve stof's comment.

It looks like the previous comment could be a better approach.

@Nyholm
Copy link
MemberAuthor

I introduced the PetriNet and StateMachine classes.

Since StateMachines and Workflows are both subtypes of PetriNet I made sure our classes reflects that. The rules@stof suggests are enforced in the constructors.

I would like to have some feedback before I continue with this PR.

Questions:

  • Do we like this approach?
  • What more rules should be applied for StateMachines/Workflows?

TODO:

  • Add more tests. For PetriNet (move from Workflow), Workflow and StateMachine
  • Review exception messages. As of now they say "Workflow" a lot.

Copy link
Member

@stofstof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm not sure this should be done in the class constructor. This means that each request in prod would run the validation of the workflow consistency again, even when the workflow is defined in the config (and so cannot change between deployments.

IMO, it would be better to have a way to validate a workflow as being a state machine externally. This way, you can have the validation running only when necessary (i.e. when changing your workflow) instead of doing it on each request.

Btw, even if we keep this constructor-based validation, I would simplify the class structure. A state machine is a workflow, so it should extend Workflow. And then, we don't need the PetriNet class anymore (the component doesnot implement PetriNet. It only implements the workflow subset of it, as transitions cannot be weighted)

Definition$definition,
MarkingStoreInterface$markingStore,
EventDispatcherInterface$dispatcher =null,
$name ='unnamed'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The signature must stay on a single line


// If the marking can contain only one place, we should control the definition
if ($markingStoreinstanceof UniqueTransitionOutputInterface) {
/** @var Transition $transition */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

this is useless if we properly document the return type ofgetTransitions asTransition[], so please remove this inline phpdoc

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thank you


$transitionFromNames =array();

/** @var Transition $transition */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

useless phpdoc

{
publicfunction__construct(Definition$definition,MarkingStoreInterface$markingStore =null,EventDispatcherInterface$dispatcher =null,$name ='unnamed')
{
if (!$markingStore) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

does it really make sense to be optional ?

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Maybe not

parent::__construct($definition,$markingStore,$dispatcher,$name);

// If the marking can contain only one place, we should control the definition
if ($markingStoreinstanceof UniqueTransitionOutputInterface) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

do we still need this interface ? It looks like a partial attempt to implement state machines IMO

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I did not introduce that interface. =)

Depending on the MarkinStore we can or cannot be in two places at the same time.


$workflowDefinition =newDefinitionDecorator('workflow.abstract');
$type =$workflow['type'];
$workflowDefinition =newDefinitionDecorator($type.'.abstract');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I would usesprintf for all string concatenation, to be consistent.

@javiereguiluz
Copy link
Member

@rvanlaak we are supper late in the Symfony 3.2 cycle (the final release is in around 20 days) so we can only merge new features if they look rock-solid, they are not huge and there is an unanimous agreement about it.

rvanlaak reacted with thumbs up emoji

@Nyholm
Copy link
MemberAuthor

Is this such PR?
It has some BC breaking changes like removal ofUniqueTransitionOutputInterface. I would hate to see us keeping that around for all 3.x versions.

@fabpot
Copy link
Member

To be clear, the only options are: reverting the Workflow component for 3.2 and wait for 3.3 to reintroduce it or merge this PR for 3.2.

@Nyholm
Copy link
MemberAuthor

To be clear, the only options are: reverting the Workflow component for 3.2 and wait for 3.3 to reintroduce it or merge this PR for 3.2.

Okey. Good. Im fine with either of those. But I would appreciate (of course) if the workflow component was introduced in 3.2.

sgomez, rvanlaak, and lyrixx reacted with thumbs up emoji

@rufinus
Copy link

Even if i dont have a saying in this.

I really looked forward to the workflow component, but without the state-machine extension it is just not usable (and i bet the most common use case for your userbase will be the state-machine).

The only thing needed for 3.2 is the changed return value (which would be a BC break after 3.2). So the state-machine itself could be added in a 3.2.1.

Of course, i would really love to see this in 3.2.0. But if I need to wait for 3.3.0 (which is 6 months away) I'm forced to use a different integration.

sgomez and theofidry reacted with thumbs up emoji

@rvanlaak
Copy link
Contributor

Is there a list of actionables for this PR to be merged already?

So the state-machine itself could be added in a 3.2.1.

Ghehe, that won't happen ;)

@stof
Copy link
Member

stof commentedNov 7, 2016

The only thing needed for 3.2 is the changed return value (which would be a BC break after 3.2). So the state-machine itself could be added in a 3.2.1.

@rufinus new features are never added in patch releases

@fabpot
Copy link
Member

@lyrixx I think we're waiting for your final approval here :)

@lyrixx
Copy link
Member

Here we go ;)

First, thanks a lot for your work on this PR. It's really cool.

For me the design is good and we could merge this one in master (3.2)

I tested this PR against my demo app, and I also tested the new state machine. Everything is in thenew branch.Warning: If you want to tests this project, you have tomanually updated symfony vendor to use this PR.

Finally, I made some modification in this PR to enhance few things. I have attached the patch to this PR.

patch:

commit ef075134f64a9b31e4d4c7ab7fc14d6c37b172bbAuthor: Grégoire Pineau <lyrixx@lyrixx.info>Date:   Mon Nov 7 18:57:54 2016 +0100    Patchdiff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.phpindex 4f1024e..09ad3dd 100644--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php@@ -35,13 +35,13 @@ class ValidateWorkflowsPass implements CompilerPassInterface         foreach ($taggedServices as $id => $tags) {             $definition = $container->get($id);             foreach ($tags as $tag) {-                if (empty($tag['name'])) {+                if (!array_key_exists('name', $tag)) {                     throw new RuntimeException(sprintf('The "name" for the tag "workflow.definition" of service "%s" must be set.', $id));                 }-                if (empty($tag['type'])) {+                if (!array_key_exists('type', $tag)) {                     throw new RuntimeException(sprintf('The "type" for the tag "workflow.definition" of service "%s" must be set.', $id));                 }-                if (empty($tag['marking_store'])) {+                if (!array_key_exists('marking_store', $tag)) {                     throw new RuntimeException(sprintf('The "marking_store" for the tag "workflow.definition" of service "%s" must be set.', $id));                 }diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.phpindex 3a1f0f0..b7cdb63 100644--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php@@ -425,7 +425,7 @@ class FrameworkExtension extends Extension                 foreach ($workflow['marking_store']['arguments'] as $argument) {                     $markingStoreDefinition->addArgument($argument);                 }-            } else {+            } elseif (isset($workflow['marking_store']['service'])) {                 $markingStoreDefinition = new Reference($workflow['marking_store']['service']);             }@@ -438,7 +438,9 @@ class FrameworkExtension extends Extension             $workflowDefinition = new DefinitionDecorator(sprintf('%s.abstract', $type));             $workflowDefinition->replaceArgument(0, $definitionDefinition);-            $workflowDefinition->replaceArgument(1, $markingStoreDefinition);+            if (isset($markingStoreDefinition)) {+                $workflowDefinition->replaceArgument(1, $markingStoreDefinition);+            }             $workflowDefinition->replaceArgument(3, $name);             $workflowId = sprintf('%s.%s', $type, $name);diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xmlindex cb8c132..1314be8 100644--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml@@ -7,13 +7,13 @@     <services>         <service abstract="true">             <argument /> <!-- workflow definition -->-            <argument /> <!-- marking store -->+            <argument type="constant">null</argument> <!-- marking store -->             <argument type="service" on-invalid="ignore" />             <argument /> <!-- name -->         </service>         <service abstract="true">             <argument /> <!-- workflow definition -->-            <argument /> <!-- marking store -->+            <argument type="constant">null</argument> <!-- marking store -->             <argument type="service" on-invalid="ignore" />             <argument /> <!-- name -->         </service>diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.phpindex 6144de1..4a7ea56 100644--- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php+++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php@@ -113,7 +113,9 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase         $subject = new \stdClass();         $subject->marking = null;         $eventDispatcher = new EventDispatcher();-        $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); });+        $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) {+            $event->setBlocked(true);+        });         $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name');         $this->assertFalse($workflow->can($subject, 't1'));@@ -188,7 +190,9 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase         $subject = new \stdClass();         $subject->marking = null;         $eventDispatcher = new EventDispatcher();-        $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); });+        $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) {+            $event->setBlocked(true);+        });         $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name');         $this->assertEmpty($workflow->getEnabledTransitions($subject));diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.phpindex 57dc632..6f34c1f 100644--- a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php+++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php@@ -53,7 +53,7 @@ class StateMachineValidator implements DefinitionValidatorInterface             if (isset($transitionFromNames[$from][$transition->getName()])) {                 throw new InvalidDefinitionException(                     sprintf(-                        'A transition from a place/state must have an unique name. Multiple transition named "%s" from place/state "%s" where found on StateMachine "%s". ',+                        'A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s". ',                         $transition->getName(),                         $from,                         $namediff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.phpindex 4e83778..348b3b9 100644--- a/src/Symfony/Component/Workflow/Workflow.php+++ b/src/Symfony/Component/Workflow/Workflow.php@@ -16,6 +16,7 @@ use Symfony\Component\Workflow\Event\Event; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Exception\LogicException; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;+use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; /**  * @author Fabien Potencier <fabien@symfony.com>@@ -29,10 +30,10 @@ class Workflow     private $dispatcher;     private $name;-    public function __construct(Definition $definition, MarkingStoreInterface $markingStore, EventDispatcherInterface $dispatcher = null, $name = 'unnamed')+    public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed')     {         $this->definition = $definition;-        $this->markingStore = $markingStore;+        $this->markingStore = $markingStore ?: new PropertyAccessorMarkingStore();         $this->dispatcher = $dispatcher;         $this->name = $name;     }@@ -163,7 +164,7 @@ class Workflow      * @param Marking    $marking      * @param Transition $transition      *-     * @return bool|void boolean true if this transition is guarded, ie you cannot use it.+     * @return bool|void boolean true if this transition is guarded, ie you cannot use it      */     private function guardTransition($subject, Marking $marking, Transition $transition)     {@@ -253,25 +254,21 @@ class Workflow     {         $transitions = $this->definition->getTransitions();-        $namedTransitions = array_filter(-            $transitions,-            function (Transition $transition) use ($transitionName) {-                return $transitionName === $transition->getName();-            }-        );+        $transitions = array_filter($transitions, function (Transition $transition) use ($transitionName) {+            return $transitionName === $transition->getName();+        });-        if (empty($namedTransitions)) {-            throw new LogicException(-                sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name)-            );+        if (!$transitions) {+            throw new LogicException(sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name));         }-        return $namedTransitions;+        return $transitions;     }     /**-     * Return the first Transition in $transitions that is valid for the $subject and $marking. null is returned when-     * you cannot do any Transition in $transitions on the $subject.+     * Return the first Transition in $transitions that is valid for the+     * $subject and $marking. null is returned when you cannot do any Transition+     * in $transitions on the $subject.      *      * @param object       $subject      * @param Marking      $marking@@ -292,7 +289,5 @@ class Workflow                 return $transition;             }         }--        return;     } }

@Nyholm
Copy link
MemberAuthor

Thank you. Excellent news. =)

Do you want to apply the patch your self (I've given you permissions) or do you want me to do it now?

@NyholmNyholm removed this from the3.3 milestoneNov 7, 2016
@lyrixx
Copy link
Member

@Nyholm Thanks. I just pushed my patch in your fork. And so my commit just land in this pr ;)

👍

Nyholm reacted with thumbs up emojirvanlaak, Nyholm, chalasr, and HeahDude reacted with hooray emoji

@NyholmNyholm added this to the3.2 milestoneNov 7, 2016
@lyrixx
Copy link
Member

I just rebased the PR and squashed all your commits.

@Nyholm
Copy link
MemberAuthor

Thank you

@fabpot
Copy link
Member

Thank you@Nyholm.

@fabpotfabpot merged commit9e49198 intosymfony:masterNov 7, 2016
fabpot added a commit that referenced this pull requestNov 7, 2016
…yholm, lyrixx)This PR was merged into the 3.2-dev branch.Discussion----------[Workflow] Make the Workflow support State Machines| Q | A || --- | --- || Branch? | "master" || Bug fix? | no || New feature? | yes || BC breaks? | yes, getEnabledTransistions does not return an assoc array. || Deprecations? | no || Tests pass? | yes || Fixed tickets |Fixes#19605,Closes#19607 || License | MIT || Doc PR |symfony/symfony-docs#6871 |While researching for the docs of the component I've found that:- A Workflow is a subclass of a Petri net- A state machine is subclass of a Workflow- A state machine must not be in many places simultaneously.This PR adds a new interface to the marking store that allow us to validate the transition to true if ANY _input_ (froms) place matches the _tokens_ (marking). The default behavior is that ALL input places must match the tokens.Commits-------9e49198 [Workflow] Made the code more robbust and ease on-boardingbdd3f95 Make the Workflow support State Machines
@Nyholm
Copy link
MemberAuthor

Thank you all for the feedback! You are awesome!

rvanlaak, theofidry, HeahDude, damienalexandre, yceruto, Simperfit, sgomez, rufinus, apfelbox, and jkobus reacted with hooray emoji

@rufinus
Copy link

@Nyholm is it a wanted effect that no services a created for the state-machines?
i can only get the service via theworkflow.registry - if sohttps://github.com/symfony/symfony-docs/pull/6871/files#diff-88cd4e9237fc7b4ee4e773e757d04f6eR79 needs an update.

@Nyholm
Copy link
MemberAuthor

No you should be able to get both workflows and state machines from the service container.

Let's move this conversation to the doc PR. It needs some input.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@lyrixxlyrixxlyrixx approved these changes

@stofstofstof approved these changes

Assignees

No one assigned

Projects

None yet

Milestone

3.2

Development

Successfully merging this pull request may close these issues.

[Workflow] Digging in to the workflow component

9 participants

@Nyholm@stof@ogizanagi@lyrixx@fabpot@rvanlaak@javiereguiluz@rufinus@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp