Компонент Workflow
Дата обновления перевода 2024-10-12
Компонент Workflow
Компонент Workflow предоставляет инструменты для управления рабочим процессом или конечной машиной.
Установка
1
$ composer require symfony/workflow
Note
Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно
подключить файл vendor/autoload.php
в вашем коде для включения механизма
автозагрузки классов, предоставляемых Composer. Детальнее читайте в
этой статье.
Создание рабочего процесса
Компонент Workflow предоставляет вам объектно-ориентированный способ для определения процесса или жизненного цикла, через который проходит ваш объект. Каждый шаг или этап в процессе называется местом. Вы также определяете переходы, которые описывают действие для перемещения из одного места в другое.
Набор мест и переходов создаёт определение. Рабочему процессу нужно
Definition
и способ написания состояний в объекты (т.е. экземпляр
MarkingStoreInterface).
Рассмотрите следующий пример для поста блога. Пост может иметь один из множества
предопределённых статусов (draft
, review
, rejected
, published
). В рабочем
процессе эти статусы называются местами. Вы можете определять рабочий процесс так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
use Symfony\Component\Workflow\DefinitionBuilder;
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
$definitionBuilder = new DefinitionBuilder();
$definition = $definitionBuilder->addPlaces(['draft', 'reviewed', 'rejected', 'published'])
// Переходы определяются с помощью уникального имени, исходного места и места назначения
->addTransition(new Transition('to_review', 'draft', 'reviewed'))
->addTransition(new Transition('publish', 'reviewed', 'published'))
->addTransition(new Transition('reject', 'reviewed', 'rejected'))
->build()
;
$singleState = true; // true если субъект может быть только в одном состоянии в заданное время
$property = 'currentState'; // имя свойства субъекта, где хранится состояние
$marking = new MethodMarkingStore($singleState, $property);
$workflow = new Workflow($definition, $marking);
Workflow
теперь может помочь вам решить, какие действия разрешены в посте
блога, в зависимости от того, в каком месте он находится. Он будет держать
вашу логику домена в одном месте, а не распораживать её по всему вашему приложению.
Использование
Вот пример использования рабочего процесса, определённого выше:
1 2 3 4 5 6 7 8 9 10 11
// ...
// Считайте, что $blogPost находится в месте "draft" по умолчанию
$blogPost = new BlogPost();
$workflow->can($blogPost, 'publish'); // False
$workflow->can($blogPost, 'to_review'); // True
$workflow->apply($blogPost, 'to_review'); // $blogPost is now in place "reviewed"
$workflow->can($blogPost, 'publish'); // True
$workflow->getEnabledTransitions($blogPost); // $blogPost can perform transition "publish" or "reject"
Инициализация
Если свойство вашего объекта - null
и вы хотите установить его с помощью
initial_marking
из конфигурации, вы можете вызвать метод getMarking()
,
чтобы инициализировать свойство объекта:
1 2 3 4 5 6
// ...
$blogPost = new BlogPost();
$workflow = $registry->get($blogPost);
// initiate workflow
$workflow->getMarking($blogPost);
Использование реестра Workflow
При определении нескольких рабочих процессов вы можете использовать Registry
,
который представляет собой объект, хранящий и предоставляющий доступ к различным рабочим процессам.
Реестр также поможет вам определить, поддерживает ли рабочий процесс объект, с которым вы
пытаетесь его использовать:
1 2 3 4 5 6 7 8 9 10 11
use Acme\Entity\BlogPost;
use Acme\Entity\Newsletter;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\SupportStrategy\InstanceOfSupportStrategy;
$blogPostWorkflow = ...;
$newsletterWorkflow = ...;
$registry = new Registry();
$registry->addWorkflow($blogPostWorkflow, new InstanceOfSupportStrategy(BlogPost::class));
$registry->addWorkflow($newsletterWorkflow, new InstanceOfSupportStrategy(Newsletter::class));
Затем вы можете использовать регистр, чтобы получать рабочий процесс для конкретного объекта:
1 2 3 4 5
$blogPost = new BlogPost();
$workflow = $registry->get($blogPost);
// инициировать рабочий процесс
$workflow->getMarking($blogPost);
Caution
Помните, что внедрять Registry
в ваши сервисы не рекомендуется.
Действительно, это препятствует некоторым оптимизациям, таким как ленивая загрузка,
и может привести к снижению производительности. Вместо этого всегда следует
внедрять нужный вам рабочий процесс.
Узнайте больше
Прочтите больше об использовании компонента Workflow внутри приложения Symfony.