mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-16 15:24:26 +00:00
Introduce MessageBus to handle post-signature operations asynchronously. This ensures that further steps are executed through dispatched messages, improving system scalability and performance. Implement new handlers and messages for the workflow state transitions.
141 lines
5.4 KiB
PHP
141 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* Chill is a software for social workers
|
|
*
|
|
* For the full copyright and license information, please view
|
|
* the LICENSE file that was distributed with this source code.
|
|
*/
|
|
|
|
namespace Chill\MainBundle\Workflow;
|
|
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStep;
|
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflowStepSignature;
|
|
use Chill\MainBundle\Workflow\Messenger\PostSignatureStateChangeMessage;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\Clock\ClockInterface;
|
|
use Symfony\Component\Messenger\MessageBusInterface;
|
|
use Symfony\Component\Workflow\Registry;
|
|
|
|
class SignatureStepStateChanger
|
|
{
|
|
private const LOG_PREFIX = '[SignatureStepStateChanger] ';
|
|
|
|
public function __construct(
|
|
private readonly Registry $registry,
|
|
private readonly ClockInterface $clock,
|
|
private readonly LoggerInterface $logger,
|
|
private readonly MessageBusInterface $messageBus,
|
|
) {}
|
|
|
|
public function markSignatureAsSigned(EntityWorkflowStepSignature $signature, ?int $atIndex): void
|
|
{
|
|
$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()));
|
|
}
|
|
|
|
public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void
|
|
{
|
|
$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()));
|
|
}
|
|
|
|
public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): void
|
|
{
|
|
$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 should be executed only by a system user (without any user registered)
|
|
*/
|
|
public function onPostMark(EntityWorkflowStepSignature $signature): void
|
|
{
|
|
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;
|
|
}
|
|
|
|
$previousUser = $this->getPreviousSender($signature->getStep());
|
|
|
|
if (null === $previousUser) {
|
|
$this->logger->info(self::LOG_PREFIX.'No previous user, will not apply a transition', ['signatureId' => $signature->getId()]);
|
|
|
|
return;
|
|
}
|
|
|
|
$transitionDto = new WorkflowTransitionContextDTO($entityWorkflow);
|
|
$transitionDto->futureDestUsers[] = $previousUser;
|
|
|
|
$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');
|
|
}
|
|
}
|