feature #34457 Added context to exceptions thrown in apply method (koenreiniers)

This PR was squashed before being merged into the 5.1-dev branch (closes #34457).

Discussion
----------

Added context to exceptions thrown in apply method

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       |
| License       | MIT
| Doc PR        |

During the workflow and state machines workshop at SymfonyCon, we noticed that the context in the apply method was not passed to the exceptions that are thrown. This could prove to be convenient for debugging purposes.

Commits
-------

8f86c337f7 Added context to exceptions thrown in apply method
This commit is contained in:
Fabien Potencier 2019-11-24 19:20:30 +01:00
commit 692d0e75e1
6 changed files with 36 additions and 11 deletions

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
5.1.0
-----
* Added context to `TransitionException` and its child classes whenever they are thrown in `Workflow::apply()`
5.0.0
-----

View File

@ -23,9 +23,9 @@ class NotEnabledTransitionException extends TransitionException
{
private $transitionBlockerList;
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, TransitionBlockerList $transitionBlockerList)
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, TransitionBlockerList $transitionBlockerList, array $context = [])
{
parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflow->getName()));
parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not enabled for workflow "%s".', $transitionName, $workflow->getName()), $context);
$this->transitionBlockerList = $transitionBlockerList;
}

View File

@ -22,14 +22,16 @@ class TransitionException extends LogicException
private $subject;
private $transitionName;
private $workflow;
private $context;
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, string $message)
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, string $message, array $context = [])
{
parent::__construct($message);
$this->subject = $subject;
$this->transitionName = $transitionName;
$this->workflow = $workflow;
$this->context = $context;
}
public function getSubject()
@ -46,4 +48,9 @@ class TransitionException extends LogicException
{
return $this->workflow;
}
public function getContext(): array
{
return $this->context;
}
}

View File

@ -20,8 +20,8 @@ use Symfony\Component\Workflow\WorkflowInterface;
*/
class UndefinedTransitionException extends TransitionException
{
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow)
public function __construct(object $subject, string $transitionName, WorkflowInterface $workflow, array $context = [])
{
parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflow->getName()));
parent::__construct($subject, $transitionName, $workflow, sprintf('Transition "%s" is not defined for workflow "%s".', $transitionName, $workflow->getName()), $context);
}
}

View File

@ -9,6 +9,7 @@ use Symfony\Component\Workflow\Event\Event;
use Symfony\Component\Workflow\Event\GuardEvent;
use Symfony\Component\Workflow\Event\TransitionEvent;
use Symfony\Component\Workflow\Exception\NotEnabledTransitionException;
use Symfony\Component\Workflow\Exception\UndefinedTransitionException;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
@ -249,13 +250,21 @@ class WorkflowTest extends TestCase
public function testApplyWithNotExisingTransition()
{
$this->expectException('Symfony\Component\Workflow\Exception\UndefinedTransitionException');
$this->expectExceptionMessage('Transition "404 Not Found" is not defined for workflow "unnamed".');
$definition = $this->createComplexWorkflowDefinition();
$subject = new Subject();
$workflow = new Workflow($definition, new MethodMarkingStore());
$context = [
'lorem' => 'ipsum',
];
$workflow->apply($subject, '404 Not Found');
try {
$workflow->apply($subject, '404 Not Found', $context);
$this->fail('Should throw an exception');
} catch (UndefinedTransitionException $e) {
$this->assertSame('Transition "404 Not Found" is not defined for workflow "unnamed".', $e->getMessage());
$this->assertSame($e->getContext(), $context);
}
}
public function testApplyWithNotEnabledTransition()
@ -263,9 +272,12 @@ class WorkflowTest extends TestCase
$definition = $this->createComplexWorkflowDefinition();
$subject = new Subject();
$workflow = new Workflow($definition, new MethodMarkingStore());
$context = [
'lorem' => 'ipsum',
];
try {
$workflow->apply($subject, 't2');
$workflow->apply($subject, 't2', $context);
$this->fail('Should throw an exception');
} catch (NotEnabledTransitionException $e) {
@ -276,6 +288,7 @@ class WorkflowTest extends TestCase
$this->assertSame($e->getWorkflow(), $workflow);
$this->assertSame($e->getSubject(), $subject);
$this->assertSame($e->getTransitionName(), 't2');
$this->assertSame($e->getContext(), $context);
}
}

View File

@ -189,11 +189,11 @@ class Workflow implements WorkflowInterface
}
if (!$transitionBlockerList) {
throw new UndefinedTransitionException($subject, $transitionName, $this);
throw new UndefinedTransitionException($subject, $transitionName, $this, $context);
}
if (!$applied) {
throw new NotEnabledTransitionException($subject, $transitionName, $this, $transitionBlockerList);
throw new NotEnabledTransitionException($subject, $transitionName, $this, $transitionBlockerList, $context);
}
return $marking;