symfony/symfony — pull request #11882 by lyrixx (2014-09-08 16:55:24+00:00)
Title: [WIP][Worflow] Introducing the workflow component

[WIP][Worflow] Introducing the workflow component

| Q | A
| ------------- | ---
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | not yet
| Fixed tickets | n/a
| License | MIT
| Doc PR | n/a

This is basically a component that implements a state-machine.

Right now it's a simple implementation, but it can lead to a full implementation
of [coloured Petri nets](http://en.wikipedia.org/wiki/Petri_net). A lot of
things should be done before a merge.

So why another component?

This component take another approach that what you can find on
[Packagist](https://packagist.org/search/?q=state%20machine).

Here, the statemachine is not tied to a specific object like with
[Finite](https://github.com/yohang/Finite). It means that the component workflow
is stateless and can be a symfony service.
Then the ObjectProperty can be anything, thanks to the PropertyPath Component.

(BTW, we are already using this component in production ;))

Some code:

use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;

$fooDefinition = new Definition('Acme\\Bundle\\AcmeBundle\\Entity\\Foo');
$fooDefinition->addStates(array(
'new', 'pending', 'finished'
));

// name from to
$fooDefinition->addTransition(new Transition('process', 'new', 'pending'));
$fooDefinition->addTransition(new Transition('finish', 'pending', 'finished'));

$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
$workflow = new Workflow('foo', $fooDefinition, $dispatcher);
$workflow->setStateProperty('internalState');

$foo = new Foo();
$state = $workflow->getState($foor);
echo $state; // 'new'

if ($workflow->can($order, 'finish')) {
// This is not possible to pass from "new" to "finished"
$workflow->apply($order, 'finish');
}

$workflow->apply($order, 'process');

$state = $workflow->getState($foor);
echo $state; // 'pending'