/** * @param StateMachineEvent $event * @param StateMachineContext $context * @return bool * @throws Exception * @throws \yii\db\Exception */ public function transition(StateMachineEvent $event, StateMachineContext $context) { // Let the context know which event triggered the transition $context->setEvent($event); /** @var yii\db\Transaction|false $txn */ $txn = $this->useTransactions ? $context->getModel()->getDb()->beginTransaction() : false; try { // Leaving current state... foreach ($event->getState()->getExitCommands() as $command) { if (!$command->execute($context)) { $txn && $txn->rollBack(); return false; } } // Cleanup old timeouts Timeout::cleanUp($context); // Entering new state... $context->getModel()->{$context->getAttr()} = $event->getTarget(); foreach ($event->getTargetState()->getEnterCommands() as $command) { if (!$command->execute($context)) { $txn && $txn->rollBack(); return false; } } // Register the new timeouts foreach ($event->getTargetState()->getTimeOuts() as $timeout) { $timeout->register($context); } // Persist the context's model data $context->getModel()->save(); // Update Journal - if applicable if ($this->modelJournal) { $journal = $this->modelJournal; /** @var StateMachineJournal $journal */ $journal::nu($context, $event); } $txn && $txn->commit(); // transition completed successfully return true; } catch (Exception $e) { $txn && $txn->rollBack(); $context->attachException($e); throw $e; } }