mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-30 14:06:13 +00:00
97 lines
3.7 KiB
PHP
97 lines
3.7 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\Service\Workflow;
|
|
|
|
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
|
|
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\Clock\ClockInterface;
|
|
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
|
|
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
|
|
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
|
|
use Symfony\Component\Workflow\Registry;
|
|
use Symfony\Component\Workflow\Transition;
|
|
|
|
#[AsMessageHandler]
|
|
final readonly class CancelStaleWorkflowHandler
|
|
{
|
|
private const LOG_PREFIX = '[CancelStaleWorkflowHandler] ';
|
|
|
|
public function __construct(
|
|
private EntityWorkflowRepository $workflowRepository,
|
|
private Registry $registry,
|
|
private EntityManagerInterface $em,
|
|
private LoggerInterface $logger,
|
|
private ClockInterface $clock,
|
|
) {}
|
|
|
|
public function __invoke(CancelStaleWorkflowMessage $message): void
|
|
{
|
|
$workflowId = $message->getWorkflowId();
|
|
$olderThanDate = $this->clock->now()->sub(new \DateInterval(CancelStaleWorkflowCronJob::KEEP_INTERVAL));
|
|
|
|
$workflow = $this->workflowRepository->find($message->getWorkflowId());
|
|
if (null === $workflow) {
|
|
$this->logger->alert(self::LOG_PREFIX.'Workflow was not found!', ['entityWorkflowId' => $workflowId]);
|
|
|
|
return;
|
|
}
|
|
|
|
if (false === $workflow->isStaledAt($olderThanDate)) {
|
|
$this->logger->alert(self::LOG_PREFIX.'Workflow has transitioned in the meantime.', ['entityWorkflowId' => $workflowId]);
|
|
|
|
throw new UnrecoverableMessageHandlingException('the workflow is not staled any more');
|
|
}
|
|
|
|
$workflowComponent = $this->registry->get($workflow, $workflow->getWorkflowName());
|
|
$metadataStore = $workflowComponent->getMetadataStore();
|
|
$transitions = $workflowComponent->getEnabledTransitions($workflow);
|
|
|
|
$transitionApplied = false;
|
|
|
|
foreach ($transitions as $transition) {
|
|
if ($this->willTransitionLeadToFinalNegative($transition, $metadataStore)) {
|
|
$dto = new WorkflowTransitionContextDTO($workflow);
|
|
$workflowComponent->apply($workflow, $transition->getName(), [
|
|
'context' => $dto,
|
|
'byUser' => null,
|
|
'transitionAt' => $this->clock->now(),
|
|
'transition' => $transition->getName(),
|
|
]);
|
|
$this->logger->info(self::LOG_PREFIX.'EntityWorkflow has been cancelled automatically.', ['entityWorkflowId' => $workflowId]);
|
|
$transitionApplied = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$transitionApplied) {
|
|
$this->logger->error(self::LOG_PREFIX.'No valid transition found for EntityWorkflow.', ['entityWorkflowId' => $workflowId]);
|
|
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
|
|
}
|
|
|
|
$this->em->flush();
|
|
}
|
|
|
|
private function willTransitionLeadToFinalNegative(Transition $transition, MetadataStoreInterface $metadataStore): bool
|
|
{
|
|
foreach ($transition->getTos() as $place) {
|
|
$metadata = $metadataStore->getPlaceMetadata($place);
|
|
if (($metadata['isFinal'] ?? true) && false === ($metadata['isFinalPositive'] ?? true)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|