entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE); $signature ->setState(EntityWorkflowSignatureStateEnum::SIGNED) ->setZoneSignatureIndex($atIndex) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as signed', ['signatureId' => $signature->getId(), 'index' => (string) $atIndex]); $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } /** * Marks a signature as canceled. * * This method will acquire a lock on the database side, so it must be wrapped into an explicit * transaction. * * This method updates the signature state to 'canceled' and logs the action. * It also dispatches a message to notify about the state change. */ public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void { $this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE); $signature ->setState(EntityWorkflowSignatureStateEnum::CANCELED) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as canceled', ['signatureId' => $signature->getId()]); $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } /** * Marks the given signature as rejected and updates its state and state date accordingly. * * This method will acquire a lock on the database side, so it must be wrapped into an explicit * transaction. * * This method logs the rejection of the signature and dispatches a message indicating * a state change has occurred. * * @param EntityWorkflowStepSignature $signature the signature entity to be marked as rejected */ public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): void { $this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE); $signature ->setState(EntityWorkflowSignatureStateEnum::REJECTED) ->setStateDate($this->clock->now()); $this->logger->info(self::LOG_PREFIX.'Mark signature entity as rejected', ['signatureId' => $signature->getId()]); $this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId())); } /** * Executed after a signature has a new state. * * This method will acquire a lock on the database side, so it must be wrapped into an explicit * transaction. * * This should be executed only by a system user (without any user registered) */ public function onPostMark(EntityWorkflowStepSignature $signature): void { $this->entityManager->refresh($signature, LockMode::PESSIMISTIC_READ); if (!EntityWorkflowStepSignature::isAllSignatureNotPendingForStep($signature->getStep())) { $this->logger->info(self::LOG_PREFIX.'This is not the last signature, skipping transition to another place', ['signatureId' => $signature->getId()]); return; } $this->logger->debug(self::LOG_PREFIX.'Continuing the process to find a transition', ['signatureId' => $signature->getId()]); $entityWorkflow = $signature->getStep()->getEntityWorkflow(); $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName()); $metadataStore = $workflow->getMetadataStore(); // find a transition $marking = $workflow->getMarking($entityWorkflow); $places = $marking->getPlaces(); $transition = null; foreach ($places as $place => $int) { $metadata = $metadataStore->getPlaceMetadata($place); if (array_key_exists('onSignatureCompleted', $metadata)) { $transition = $metadata['onSignatureCompleted']['transitionName']; } } if (null === $transition) { $this->logger->info(self::LOG_PREFIX.'The transition is not configured, will not apply a transition', ['signatureId' => $signature->getId()]); return; } if ('person' === $signature->getSignerKind()) { $futureUser = $this->getPreviousSender($signature->getStep()); } else { $futureUser = $signature->getSigner(); } if (null === $futureUser) { $this->logger->info(self::LOG_PREFIX.'No previous user, will not apply a transition', ['signatureId' => $signature->getId()]); return; } $transitionDto = new WorkflowTransitionContextDTO($entityWorkflow); $transitionDto->futureDestUsers[] = $futureUser; $workflow->apply($entityWorkflow, $transition, [ 'context' => $transitionDto, 'transitionAt' => $this->clock->now(), 'transition' => $transition, ]); $this->logger->info(self::LOG_PREFIX.'Transition automatically applied', ['signatureId' => $signature->getId()]); } private function getPreviousSender(EntityWorkflowStep $entityWorkflowStep): ?User { $stepsChained = $entityWorkflowStep->getEntityWorkflow()->getStepsChained(); foreach ($stepsChained as $stepChained) { if ($stepChained === $entityWorkflowStep) { if (null === $previous = $stepChained->getPrevious()) { return null; } if (null !== $previousUser = $previous->getTransitionBy()) { return $previousUser; } return $this->getPreviousSender($previous); } } throw new \LogicException('no same step found'); } }