Skip to content

[PoC] [Workflow] Allowed using multiple tokens by places #20508

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\MultipleStateMarking;
use Symfony\Component\Workflow\SingleStateMarking;
use Symfony\Component\Workflow\StateMachine;

/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
Expand Down Expand Up @@ -67,7 +68,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$dumper = new GraphvizDumper();
$marking = new Marking();
$marking = $workflow instanceof StateMachine ? new SingleStateMarking() : new MultipleStateMarking();

foreach ($input->getArgument('marking') as $place) {
$marking->mark($place);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
->children()
->enumNode('type')
->values(array('multiple_state', 'single_state'))
->defaultValue('multiple_state')
->end()
->arrayNode('arguments')
->beforeNormalization()
Expand Down Expand Up @@ -281,6 +282,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
->end()
->end()
->end()
->booleanNode('use_tokens')->defaultFalse()->end()
->arrayNode('places')
->isRequired()
->requiresAtLeastOneElement()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,13 +431,16 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
));

// Create MarkingStore
if (isset($workflow['marking_store']['type'])) {
$markingStoreDefinition = new DefinitionDecorator('workflow.marking_store.'.$workflow['marking_store']['type']);
if (isset($workflow['marking_store']['service'])) {
$markingStoreDefinition = new Reference($workflow['marking_store']['service']);
} else {
$markingStoreDefinition = new DefinitionDecorator('workflow.marking_store.property_access');
foreach ($workflow['marking_store']['arguments'] as $argument) {
$markingStoreDefinition->addArgument($argument);
}
} elseif (isset($workflow['marking_store']['service'])) {
$markingStoreDefinition = new Reference($workflow['marking_store']['service']);

$markingStrategy = 'state_machine' === $type ? 'single_state' : $workflow['marking_store']['type'];
$markingStoreDefinition->replaceArgument(2, $markingStrategy);
}

// Create Workflow
Expand All @@ -447,6 +450,9 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde
$workflowDefinition->replaceArgument(1, $markingStoreDefinition);
}
$workflowDefinition->replaceArgument(3, $name);
if ('workflow' === $type) {
$workflowDefinition->replaceArgument(4, $workflow['use_tokens']);
}

// Store to container
$workflowId = sprintf('%s.%s', $type, $name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
<argument /> <!-- name -->
</service>

<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.property_access" class="Symfony\Component\Workflow\MarkingStore\PropertyAccessMarkingStore" abstract="true" />

<service id="workflow.registry" class="Symfony\Component\Workflow\Registry" />

Expand Down
33 changes: 33 additions & 0 deletions src/Symfony/Component/Workflow/EventListener/WorkflowListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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\EventListener;

use Symfony\Component\Workflow\Event\GuardEvent;

/**
* @author Jules Pietri <jules@heahprod.com>
*/
class WorkflowListener
{
public function __invoke(GuardEvent $event)
{
$marking = $event->getMarking();

foreach ($event->getTransition()->getTos() as $to) {
if (!$marking->has($to)) {
Copy link
Member

Choose a reason for hiding this comment

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

This looks weird to me. Why checking the target and blocking if we already have a marking there ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the listener is only guarding when there is no support for many tokens in one place.

return;
}
}

$event->setBlocked(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?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\Exception;

/**
* An InvalidMarkingException is thrown when a Marking does not
* match the current workflow.
*
* @author Jules Pietri <jules@heahprod.com>
*/
class InvalidMarkingException extends LogicException
{
/**
* @param string $expectedClass
* @param mixed $marking
*/
public function __construct($expectedClass, $marking)
{
$this->message = sprintf('Marking must be an instance of "%", but got "%"', $expectedClass, is_object($marking) ? get_class($marking) : gettype($marking));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?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\Exception;

/**
* An InvalidMarkingStrategyException is thrown when the marking strategy
* does not match the Marking instance.
*
* @author Jules Pietri <jules@heahprod.com>
*/
class InvalidMarkingStrategyException extends LogicException
{
/**
* @param string $markingStoreClass
*/
public function __construct($markingStoreClass)
{
$this->message = sprintf('The marking store has no strategy set. Did you forgot to call "%::__construct()"?', $markingStoreClass);
}
}
50 changes: 27 additions & 23 deletions src/Symfony/Component/Workflow/Marking.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,45 @@
namespace Symfony\Component\Workflow;

/**
* Marking contains the place of every tokens.
* A base Marking which contains the state of the
* state of a Workflow or a StateMachine a representation
* by places with tokens.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Jules Pietri <jules@heahprod.com>
*/
class Marking
abstract class Marking
{
private $places = array();
const STRATEGY_SINGLE_STATE = 'single_state';
const STRATEGY_MULTIPLE_STATE = 'multiple_state';

protected $places = array();

/**
* @param string[] $representation Keys are the place name and values should be 1
* @param string $place
*
* @return bool
*/
public function __construct(array $representation = array())
{
foreach ($representation as $place => $nbToken) {
$this->mark($place);
}
}

public function mark($place)
{
$this->places[$place] = 1;
}

public function unmark($place)
{
unset($this->places[$place]);
}

public function has($place)
final public function has($place)
{
return isset($this->places[$place]);
}

public function getPlaces()
/**
* @return int[] An array of places as keys and token counts as values.
*/
final public function getState()
{
return $this->places;
}

/**
* @param string $place
*/
abstract public function mark($place);

/**
* @param string $place
*/
abstract public function unmark($place);
}
Loading