Рабочие процессы и машины состояний

Дата обновления перевода 2022-12-23

Рабочие процессы и машины состояний

Рабочие процессы

Рабочий процесс - это модель процесса в вашем приложении. Это может быть процесс того, как пост блога проходит этапы от черновика, до рецензии, до публикации. Другой пример - когда пользователь отправляет несколько разных форм для выполнения задачи. Такие процессы лучше всего держать подальше от ваших моделей, и стоит определять в конфигурации.

Определение рабочего процесса состоит из мест и действий, которые нужно переместить из одного места в другое. Эти действия называются переходами. Рабочий процесс также должен знать местоположение каждого объекта в рабочем процессе. Хранилище маркировки записывает текущее место в свойство объекта.

Note

Терминология выше часто используется при обсуждении рабочих процессов и сетей Петри

Примеры

Самый простой рабочий процесс выглядит так. Он содержит два места и один переход.

Рабочие процессы могут быть более сложными, когда они описывают реальный бизнес-пример. Рабочий процесс ниже описывает процесс заполнения заявки на работу.

Когда вы заполняете заявку на работу в этом примере, у вас будет от 4 до 7 шагов, в зависимости от того, на какую работу вы подаетесь. Некоторые виды работы требуют тестов личности, тестов на логику и/или формальных требований, на которые должен ответить пользователь. Некоторые - не требуют этого. GuardEvent используется для того, какие следующие шаги разрешены для конкретной заявки.

Определяя рабочий процесс таким образом, существует обзор того, как выглядит процесс. Логика процесса не смешивается с контроллерами, моделями или просмотром. Порядок шагов может быть изменен только путем изменения конфигурации.

Машины состояний

Машина состояний - это подмножество рабочего процесса, целью которого является содержание состояние вашей модели. Наиболее важные различия между ними:

  • Рабочие процессы могут быть больше, чем в одном месте одновременно, а машины состояний - нет;
  • Для того, чтобы применить переход, рабочие процессы требуют того, чтобы объект был во всех предыдущих местах перехода, в то время как машины состояний требуют только чтобы объект был хотя бы в одном из этих мест.

Пример

Запрос на включение запускает изначальное "стартовое" состояние, а затем состояние "тестирования", для, например, выполнения тестов в непрерывном стеке интеграции. Когда оно будет закончено, запрос на включение переходит в состояние "рецензии", где можно запросить изменения, принять или отклонить запрос на включение. В любое время, вы также можете "обновить" запрос на включение, что приведет к новому запуску беспрерывной интеграции.

Ниже можно увидеть конфигурацию запроса на включение машины состояний.

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# config/packages/workflow.yaml
framework:
    workflows:
        pull_request:
            type: 'state_machine'
            marking_store:
                 type: 'method'
                 property: 'currentPlace'
            supports:
                - App\Entity\PullRequest
            initial_marking: start
            places:
                - start
                - coding
                - test
                - review
                - merged
                - closed
            transitions:
                submit:
                    from: start
                    to: test
                update:
                    from: [coding, test, review]
                    to: test
                wait_for_review:
                    from: test
                    to: review
                request_change:
                    from: review
                    to: coding
                accept:
                    from: review
                    to: merged
                reject:
                    from: review
                    to: closed
                reopen:
                    from: closed
                    to: review

В приложении Symfony, используя конфигурацию services.yaml по умолчанию , вы можете получить эту машину состояний, внедрив сервис реестра Workflow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// ...
use App\Entity\PullRequest;
use Symfony\Component\Workflow\Registry;

class SomeService
{
    private $workflows;

    public function __construct(Registry $workflows)
    {
        $this->workflows = $workflows;
    }

    public function someMethod(PullRequest $pullRequest)
    {
        $stateMachine = $this->workflows->get($pullRequest, 'pull_request');
        $stateMachine->apply($pullRequest, 'wait_for_review');
        // ...
    }

    // ...
}

Symfony автоматически создает сервис для каждого рабочего процесса (Workflow) или машины состояний (StateMachine), которые вы определили в своей конфигурации. Это означает, что вы можете использовать workflow.pull_request или state_machine.pull_request соответственно, в ваших определениях сервиса, чтобы получить доступ к правильному сервису:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ...
use App\Entity\PullRequest;
use Symfony\Component\Workflow\StateMachine;

class SomeService
{
    private $stateMachine;

    public function __construct(StateMachine $stateMachine)
    {
        $this->stateMachine = $stateMachine;
    }

    public function someMethod(PullRequest $pullRequest)
    {
        $this->stateMachine->apply($pullRequest, 'wait_for_review', [
            'log_comment' => 'My logging comment for the wait for review transition.',
        ]);
        // ...
    }

    // ...
}

Автоматическая и ручная валидация

Во время разогрева кеша, Symfony валидирует рабочие процессы и машины состояний, которые определены в файлах конфигурации. Если ваши рабочие процессы или машины состояний определены программно, а не в файле конфигурации, вы можете валидировать их с помощью the WorkflowValidator и StateMachineValidator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ...
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\StateMachine;
use Symfony\Component\Workflow\Validator\StateMachineValidator;

$states = ['created', 'activated', 'deleted'];
$stateTransitions = [
    new Transition('activate', 'created', 'activated'),
    // Это дублированное событие "from" состояния "created" невалидно
    new Transition('activate', 'created', 'deleted'),
    new Transition('delete', 'activated', 'deleted'),
];

// При запуске валидация не проводится
$definition = new Definition($states, $stateTransitions);

$validator = new StateMachineValidator();
// Вызывает InvalidDefinitionException в случае невалидного определения
$validator->validate($definition, 'My First StateMachine');