chill-bundles/src/Bundle/ChillMainBundle/Service/Workflow/CancelStaleWorkflowHandler.php

78 lines
3.0 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 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\Registry;
#[AsMessageHandler]
class CancelStaleWorkflowHandler
{
public const string KEEP_INTERVAL = 'P90D';
public function __construct(private readonly EntityWorkflowRepository $workflowRepository, private readonly Registry $registry, private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly ClockInterface $clock) {}
public function __invoke(CancelStaleWorkflowMessage $message): void
{
$workflowId = $message->getWorkflowId();
$olderThanDate = $this->clock->now()->sub(new \DateInterval(self::KEEP_INTERVAL));
$staleWorkflows = $this->workflowRepository->findWorkflowsWithoutFinalStepAndOlderThan($olderThanDate);
$workflow = $this->workflowRepository->find($workflowId);
if (in_array($workflow, $staleWorkflows, true)) {
$this->logger->alert('Workflow has transitioned in the meantime.', [$workflowId]);
return;
}
if (null === $workflow) {
$this->logger->alert('Workflow was not found!', [$workflowId]);
return;
}
$workflowComponent = $this->registry->get($workflow, $workflow->getWorkflowName());
$metadataStore = $workflowComponent->getMetadataStore();
$transitions = $workflowComponent->getEnabledTransitions($workflow);
$steps = $workflow->getSteps();
$transitionApplied = false;
if (1 === count($steps)) {
$this->em->remove($workflow->getCurrentStep());
$this->em->remove($workflow);
} else {
foreach ($transitions as $transition) {
$isFinal = $metadataStore->getMetadata('isFinal', $transition);
$isFinalPositive = $metadataStore->getMetadata('isFinalPositive', $transition);
if ($isFinal && !$isFinalPositive) {
$workflowComponent->apply($workflow, $transition->getName());
$this->logger->info('EntityWorkflow has been cancelled automatically.', [$workflowId]);
$transitionApplied = true;
break;
}
}
if (!$transitionApplied) {
$this->logger->error('No valid transition found for EntityWorkflow %d.', [$workflowId]);
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
}
}
}
}