diff --git a/contributing/documentation/overview.rst b/contributing/documentation/overview.rst index e0fd5eac618..593fbec5b89 100644 --- a/contributing/documentation/overview.rst +++ b/contributing/documentation/overview.rst @@ -270,6 +270,10 @@ purposes following these steps: The generated documentation is available in the ``_build/html`` directory. +.. tip:: + + You can also use `Docker`_ that wraps all this for you! + Frequently Asked Questions -------------------------- @@ -332,3 +336,4 @@ definitely don't want you to waste your time! .. _`pip installation`: https://pip.pypa.io/en/stable/installing/ .. _`Sphinx`: http://sphinx-doc.org/ .. _`Sphinx Extensions for PHP and Symfony`: https://github.com/fabpot/sphinx-php +.. _`Docker`: https://github.com/symfony/symfony-docs#docker diff --git a/workflow.rst b/workflow.rst index b25e62b8379..d08b2d8e819 100644 --- a/workflow.rst +++ b/workflow.rst @@ -8,8 +8,9 @@ best kept away from your models and should be defined in configuration. A **definition** of a workflow consist of places and actions to get from one place to another. The actions are called **transitions**. A workflow does also -need to know each object's position in the workflow. That **marking store** writes -to a property of the object to remember the current place. +need to know each position an object can be in the workflow. This is the goal of the +**marking store** that reads from and writes to a property of the object, or somewhere else, the current **place(s)** +to remember. .. note:: diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 316c172214c..787d819ea4f 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -209,6 +209,33 @@ you can get this state machine by injecting the Workflow registry service:: public function someMethod($subject) { $stateMachine = $this->workflows->get($subject, 'pull_request'); + $stateMachine->apply($subject, 'wait_for_review'); + // ... + } + + // ... + } + +Symfony also creates automatically for you a service for each workflow (:class:`Symfony\\Component\\Workflow\\Workflow`) or state machine (:class:`Symfony\\Component\\Workflow\\StateMachine`) you have defined in your configuration. +This means that you can use respectively ``workflow.pull_request`` or ``state_machine.pull_request`` in your service definition to have directly the proper service:: + + // ... + use Symfony\Component\Workflow\StateMachine; + + class SomeService + { + private $stateMachine; + + public function __construct(StateMachine $stateMachine) + { + $this->stateMachine = $stateMachine; + } + + public function someMethod($subject) + { + $this->stateMachine->apply($subject, 'wait_for_review', [ + 'log_comment' => 'My logging comment for the wait for review transition.', + ]); // ... } diff --git a/workflow/usage.rst b/workflow/usage.rst index 5cbce6a79d0..fb521e21f05 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -43,7 +43,7 @@ like this: audit_trail: enabled: true marking_store: - type: 'multiple_state' # or 'single_state' + type: 'multiple_state' # or 'single_state', 'method' ('method' was added in 4.3) arguments: - 'currentPlace' supports: @@ -127,7 +127,7 @@ like this: 'enabled' => true ], 'marking_store' => [ - 'type' => 'multiple_state', // or 'single_state' + 'type' => 'multiple_state', // or 'single_state', 'method' ('method' was added in 4.3) 'arguments' => ['currentPlace'], ], 'supports' => ['App\Entity\BlogPost'], @@ -167,7 +167,7 @@ As configured, the following property is used by the marking store:: .. note:: - The marking store type could be "multiple_state" or "single_state". + The marking store type could be "multiple_state", "single_state" or "method". A single state marking store does not support a model being on multiple places at the same time. @@ -221,11 +221,87 @@ you can get the workflow by injecting the Workflow registry service:: // ... if the transition is not allowed } + // Update the currentState on the post passing some contextual data + // to the whole workflow process + try { + $workflow->apply($post, 'publish', [ + 'log_comment' => 'My logging comment for the publish transition.', + ]); + } catch (TransitionException $exception) { + // ... if the transition is not allowed + } + // See all the available transitions for the post in the current state $transitions = $workflow->getEnabledTransitions($post); } } +.. versionadded:: 4.1 + + The :class:`Symfony\\Component\\Workflow\\Exception\\TransitionException` + class was introduced in Symfony 4.1. + +.. versionadded:: 4.1 + + The :method:`Symfony\\Component\\Workflow\\Registry::all` method was + introduced in Symfony 4.1. + +.. versionadded:: 4.3 + + The :method:`Symfony\\Component\\Workflow\\Workflow::apply` has now a new parameter ``$context`` + that is passed to the :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface` + :method:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface::setMarking` method. + +An example of usage with the ``$context`` parameter can be when you need, +in addition of marking your object in its new place, to contextualize this change. + +.. tip:: + + Configure the ``type`` as ``method`` of the ``marking_store`` option to use this feature + without implementing your own marking store. + +You can also use this ``$context`` in your own marking store implementation. +A simple implementation example is when you want to store the place as integer instead of string in your object. + +Lets say your object has a status property, stored as an integer in your storage, and you want to log an optional +comment any time the status changes:: + + // your own implementation class, to define in the configuration "marking_store" + + class ObjectMarkingStore implements MarkingStoreInterface + { + public function getMarking($subject) + { + $subject->getStatus(); + // ... + // return a marking + } + + public function setMarking($subject, Marking $marking, array $context); + { + // ... + $subject->setStatus($newStatus, $context['log_comment'] ?? null); + } + } + + // and in your Object class + + public function getStatus() + { + return $this->status; + } + + public function setStatus(int $status, ?string $comment = null) + { + $this->status = $status; + $this->addStatusLogRecord(new StatusLog($this, $comment)); + + return $this; + } + + // the StatusLog class can have a createdAt, a username, + // the new status, and finally your optional comment retrieved from the workflow context. + Using Events ------------