В приложениях часто необходимо ограничивать доступ к тем или иным действиям над объектом. Для этого используют RBAC-модули, которые решают задачу ограничения доступа в зависимости от прав пользователя. Остается нерешенной задача управления действиями в зависимости от состояния объекта. Эта задача хорошо решается с помощью конечного автомата или state machine. Удобная стейтмашина позволяет не только собрать в одном месте все правила переходов между состояниями объекта, но и наводит некоторый порядок в коде отделяя правила переходов, проверки условия и обрабочкики и подчиняя их общим правилам. Хочу поделиться реализацией стейтмашины под Zend Framework 3 с использованием Doctrine 2
для работы с базой данных. Сам проект можно найти по ссылке. А здесь я хочу поделиться основными заложенными принципами. Приступим Описание графа переходов мы будем хранить в таблице базы данных потому что: Использование недетерминированного конечного автомата повысит гибкость нашего решения.  Граф переходов будем описывать с помощью пары таблиц A и B, связанных между собой отношением один ко многим. Таблица A: Таблица B: Определение классов энтити я опущу, посмотреть пример можно здесь: Здесь все стандартно, включая описание связи между сущностями. Для использования стейтмашины нам необходимы всего несколько публичных методов Для комфортного использования есть еще несколько публичных методов, но здесь я бы хотел уделить внимания алгоритму работы основного метода doAction().  Из объекта получаем его состояние. Зная его и идентификатор действия легко отыскивается ентити-А в таблице перехода А.
Условие полученное по идентификатору условия, который лежит в condition из ентити-А, позволяет проверить возможность выполнения действия. В частности в валидаторе условия может быть использован упомянутый вначале статьи RBAC. Валидатор будет найден по идентификатору из поля condition через ValidatorPluginManager и
должен реализовывать \Zend\Validator\ValidatorInterface. Я предпочитаю использовать наследников от ValidatorChain. Это позволяет легко менять состав контролируемых условий и переиспользовать простые валидаторы в составе проверочных цепочек. С переходом определились, условие проверили. Так как у нас недетерминированный
конечный автомат, то результатом действия может быть одно из нескольких состояний.  Такие случаи встречаются не очень часто, но предлагаемый проект это легко реализует.
По связи А --< B получаем коллекцию возможных новых состояний объекта (энтити-B).
Чтобы выбрать единственное состояние проверяем по очереди условия у энтити-B из полученной коллекции, отсортировав их по полю weight от большего к меньшему. Первая успешная проверка условия дает нам энтити-B, в которой есть новое состояние объекта (смотри поле dst_id). Новое состояние определено. Теперь перед сменой состояния стейтмашина выполнит
действия, определенные в префункторе, затем сменит состояние и выполнит действия,
определенные в постфункторе. Стейтмашина достанет функторы на основании имени из поля pre_functor для префунктора и post_functor для постфунктора с помощью плагин-менеджера и вызовет метод для полученных объектов метод __invoke(). Менять состояние с помощью функторов не нужно. Это задача стейтмашины. Если нет необходимости выполнять дополнительные действия при смене состояния, то в указанные выше поля ставим null.  Прочие фишки: Несмотря на множество задач, идеально подходящих под использование стейтмашин, веб-программисты используют их сравнительно редко. Те же решения, которые я видел, показались мне монстровитыми.  Надеюсь, что предложенное решение поможет кому-нибудь сэкономить время на реализацию.