From e1c0e04057941dbf25ce1ed3672661b1c9d88ed6 Mon Sep 17 00:00:00 2001 From: Peter Bowyer Date: Sat, 23 Mar 2019 11:39:09 +0000 Subject: [PATCH 1/4] Document 4.3 `marking_store` changes. Have reservations from a DX perspective, see https://github.com/symfony/symfony/pull/30551/files#r268391471 --- workflow/usage.rst | 178 +++++---------------------------------------- 1 file changed, 17 insertions(+), 161 deletions(-) diff --git a/workflow/usage.rst b/workflow/usage.rst index c613b76dd3a..5fa3563b9aa 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -43,8 +43,9 @@ like this: audit_trail: enabled: true marking_store: - type: 'multiple_state' # one of 'single_state', 'multiple_state', 'method' + type: 'method' arguments: + - false - 'currentPlace' supports: - App\Entity\BlogPost @@ -68,7 +69,7 @@ like this: .. code-block:: xml - + - + + false currentPlace @@ -117,6 +119,7 @@ like this: .. code-block:: php // config/packages/workflow.php + $container->loadFromExtension('framework', [ // ... 'workflows' => [ @@ -126,8 +129,11 @@ like this: 'enabled' => true ], 'marking_store' => [ - 'type' => 'multiple_state', // one of 'single_state', 'multiple_state', 'method' - 'arguments' => ['currentPlace'], + 'type' => 'method', + 'arguments' => [ + false, + 'currentPlace', + ], ], 'supports' => ['App\Entity\BlogPost'], 'places' => [ @@ -166,18 +172,14 @@ As configured, the following property is used by the marking store:: .. note:: - 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. - - versionadded:: 4.3 - - The ``method`` marking store type was introduced in Symfony 4.3. + The Workflow Component supports workflows that can be in one or multiple places + (states) at the same time. To restrict a workflow to a single state, set the first + argument to ``true`` when defining the ``marking_store``. .. tip:: - The ``type`` (default value ``single_state``) and ``arguments`` (default - value ``marking``) attributes of the ``marking_store`` option are optional. + The ``type`` (default value ``method``) and ``arguments`` (default + values ``false`` and ``marking``) attributes of the ``marking_store`` option are optional. If omitted, their default values will be used. .. tip:: @@ -224,90 +226,11 @@ 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. - -You can pass some context as the second argument of the ``apply()`` method. -This can be useful when the subject not only needs to apply a transition, -but for example you also want to log the context in which the switch happened. - -This context is forwarded to the :method:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface::setMarking` -method of the marking store. - -.. versionadded:: 4.3 - - The ``$context`` argument of the :method:`Symfony\\Component\\Workflow\\Workflow::apply` - method was introduced in Symfony 4.3. - -.. 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 ------------ @@ -455,7 +378,7 @@ See example to make sure no blog post without title is moved to "review":: { public function guardReview(GuardEvent $event) { - /** @var App\Entity\BlogPost $post */ + /** @var \App\Entity\BlogPost $post */ $post = $event->getSubject(); $title = $post->title; @@ -549,70 +472,3 @@ The following example shows these functions in action: {% if 'waiting_some_approval' in workflow_marked_places(post) %} PENDING {% endif %} - -Transition Blockers -------------------- - -.. versionadded:: 4.1 - - Transition Blockers were introduced in Symfony 4.1. - -Transition Blockers provide a way to return a human-readable message for why a -transition was blocked:: - - use Symfony\Component\Workflow\Event\GuardEvent; - use Symfony\Component\EventDispatcher\EventSubscriberInterface; - - class BlogPostPublishListener implements EventSubscriberInterface - { - public function guardPublish(GuardEvent $event) - { - /** @var \App\Entity\BlogPost $post */ - $post = $event->getSubject(); - - // If it's after 9pm, prevent publication - if (date('H') > 21) { - $event->addTransitionBlocker( - new TransitionBlocker( - "You can not publish this blog post because it's too late. Try again tomorrow morning." - ) - ); - } - } - - public static function getSubscribedEvents() - { - return [ - 'workflow.blogpost.guard.publish' => ['guardPublish'], - ]; - } - } - -You can access the message from a Twig template as follows: - -.. code-block:: html+twig - -

Publication was blocked because:

-
    - {% for transition in workflow_all_transitions(article) %} - {% if not workflow_can(article, transition.name) %} -
  • - {{ transition.name }}: -
      - {% for blocker in workflow_build_transition_blocker_list(article, transition.name) %} -
    • - {{ blocker.message }} - {% if blocker.parameters.expression is defined %} - {{ blocker.parameters.expression }} - {% endif %} -
    • - {% endfor %} -
    -
  • - {% endif %} - {% endfor %} -
- -Don't need a human-readable message? You can still use:: - - $event->setBlocked('true'); From 6c636cbd5e24f59aaeda375b0e62dd340ee24a1e Mon Sep 17 00:00:00 2001 From: Peter Bowyer Date: Sat, 23 Mar 2019 11:49:44 +0000 Subject: [PATCH 2/4] Update `initial_place` to `initial_places`. Add missing `initial_places` to PHP configuration example. Someone needs to add it to the XML --- workflow/usage.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow/usage.rst b/workflow/usage.rst index 5fa3563b9aa..b97e402a65d 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -49,7 +49,7 @@ like this: - 'currentPlace' supports: - App\Entity\BlogPost - initial_place: draft + initial_places: [draft] places: - draft - review @@ -136,6 +136,7 @@ like this: ], ], 'supports' => ['App\Entity\BlogPost'], + 'initial_places' => ['draft'], 'places' => [ 'draft', 'review', From 6cac400bfb9e87fc37e9cc6ee04d8a8548fd187b Mon Sep 17 00:00:00 2001 From: Peter Bowyer Date: Sun, 7 Apr 2019 13:52:20 +0100 Subject: [PATCH 3/4] Incorporate feedback from @lyrixx --- workflow/usage.rst | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/workflow/usage.rst b/workflow/usage.rst index b97e402a65d..cd09df8deea 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -43,13 +43,12 @@ like this: audit_trail: enabled: true marking_store: - type: 'method' - arguments: - - false - - 'currentPlace' + # Method will become the default value in Symfony 5.0 + type: method + property: currentPlace supports: - App\Entity\BlogPost - initial_places: [draft] + initial_marking: [draft] places: - draft - review @@ -81,10 +80,9 @@ like this: - - false - currentPlace - + draft + + App\Entity\BlogPost @@ -129,14 +127,12 @@ like this: 'enabled' => true ], 'marking_store' => [ + // Method will become the default value in Symfony 5.0 'type' => 'method', - 'arguments' => [ - false, - 'currentPlace', - ], + 'property' => 'currentPlace', ], 'supports' => ['App\Entity\BlogPost'], - 'initial_places' => ['draft'], + 'initial_marking' => ['draft'], 'places' => [ 'draft', 'review', @@ -174,14 +170,18 @@ As configured, the following property is used by the marking store:: .. note:: The Workflow Component supports workflows that can be in one or multiple places - (states) at the same time. To restrict a workflow to a single state, set the first - argument to ``true`` when defining the ``marking_store``. + (states) at the same time. + + If the subject can be in only on state: use a state machine. In that case, the + property (named ``marking`` by default) will be a string. + + If the subject can be in many places: use a workflow. In that case, the property will be an array. .. tip:: - The ``type`` (default value ``method``) and ``arguments`` (default - values ``false`` and ``marking``) attributes of the ``marking_store`` option are optional. - If omitted, their default values will be used. + The ``type`` (default value ``method``) and ``property`` (default + value ``marking``) attributes of the ``marking_store`` option are optional. + If omitted, the default values will be used. .. tip:: From 4320d542c3bbf37b6489c15bae76e22e6e6abb1f Mon Sep 17 00:00:00 2001 From: Peter Bowyer Date: Sun, 7 Apr 2019 15:40:02 +0100 Subject: [PATCH 4/4] Change to `initial_marking` in the State Machine documentation --- workflow/state-machines.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 4a5952c9f1d..11d03896cd9 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -35,7 +35,7 @@ Below is the configuration for the pull request state machine. type: 'state_machine' supports: - App\Entity\PullRequest - initial_place: start + initial_marking: [start] places: - start - coding @@ -79,7 +79,7 @@ Below is the configuration for the pull request state machine. - + start App\Entity\PullRequest @@ -147,6 +147,7 @@ Below is the configuration for the pull request state machine. 'workflows' => [ 'pull_request' => [ 'type' => 'state_machine', + 'initial_marking' => ['start'] 'supports' => ['App\Entity\PullRequest'], 'places' => [ 'start',