Browse Source

Workflow mis à jour, fonctionnel

François Drouhard 1 month ago
parent
commit
f059fb6a53

+ 27 - 1
config/packages/workflow.yaml

@@ -1,2 +1,28 @@
 framework:
-    workflows: null
+    workflows:
+        countdown:
+            type: 'state_machine'
+            audit_trail:
+                enabled: true
+            marking_store:
+                type: 'method'
+                property: 'state'
+            supports:
+                - App\Entity\Counter
+            initial_marking: !php/const App\Entity\Counter::STATE_READY
+            places:
+                - !php/const App\Entity\Counter::STATE_READY
+                - !php/const App\Entity\Counter::STATE_STARTED
+                - !php/const App\Entity\Counter::STATE_COMPLETED
+            transitions:
+                !php/const App\Entity\Counter::TRANSITION_TO_STARTED:
+                    from: !php/const App\Entity\Counter::STATE_READY
+                    to: !php/const App\Entity\Counter::STATE_STARTED
+                !php/const App\Entity\Counter::TRANSITION_TO_COMPLETED:
+                    from: !php/const App\Entity\Counter::STATE_STARTED
+                    to: !php/const App\Entity\Counter::STATE_COMPLETED
+                !php/const App\Entity\Counter::TRANSITION_TO_READY:
+                    from: !php/const App\Entity\Counter::STATE_COMPLETED
+                    to: !php/const App\Entity\Counter::STATE_READY
+                
+            

BIN
countdownWorkflow.png


+ 31 - 0
migrations/Version20240321220956.php

@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240321220956 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE counter CHANGE start_time start_time DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', CHANGE end_time end_time DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\'');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE counter CHANGE start_time start_time TIME DEFAULT NULL COMMENT \'(DC2Type:time_immutable)\', CHANGE end_time end_time TIME DEFAULT NULL COMMENT \'(DC2Type:time_immutable)\'');
+    }
+}

+ 18 - 3
src/Controller/CounterController.php

@@ -9,12 +9,14 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Attribute\Route;
-use Symfony\Component\Serializer\SerializerInterface;
+use Symfony\Component\Workflow\WorkflowInterface;
 
 class CounterController extends AbstractController
 {
     public function __construct(
         protected CounterManager $counterManager,
+        protected WorkflowInterface $countdownStateMachine,
+        protected CounterRepository $counterRepository
     )
     {
         
@@ -23,7 +25,6 @@ class CounterController extends AbstractController
     #[Route('/counter', name: 'app_counter', methods: ['GET'])]
     public function index(CounterRepository $counterRepository): JsonResponse
     {
-        //$counter = $this->counterManager->init("P5M", "Youpi");
         $counters = $counterRepository->findAll();
         return $this->json($counters, 200);
     }
@@ -45,7 +46,21 @@ class CounterController extends AbstractController
     #[Route('/counter/start/{id}', name: 'app_counter_start')]
     public function startCounter(Counter $counter): JsonResponse
     {
-        $counter = $this->counterManager->start($counter);
+        $this->countdownStateMachine->apply($counter, Counter::TRANSITION_TO_STARTED);
+
+        return $this->json($counter, 200);
+    }
+
+    #[Route('counter/{id}', name: 'app_counter_id', methods: ['GET'])]
+    public function getCounter(Counter $counter): JsonResponse
+    {
+        return $this->json($counter, 200);
+    }
+
+    #[Route('counter/clear/{id}', name: 'app_counter_clear')]
+    public function clear(Counter $counter): JsonResponse
+    {
+        $this->countdownStateMachine->apply($counter, Counter::TRANSITION_TO_READY);
 
         return $this->json($counter, 200);
     }

+ 12 - 4
src/Entity/Counter.php

@@ -9,15 +9,23 @@ use Doctrine\ORM\Mapping as ORM;
 #[ORM\Entity(repositoryClass: CounterRepository::class)]
 class Counter
 {
+    public const STATE_READY = "ready";
+    public const STATE_STARTED = "started";
+    public const STATE_COMPLETED = "completed";
+
+    public const TRANSITION_TO_STARTED = "to_started";
+    public const TRANSITION_TO_COMPLETED = "to_completed";
+    public const TRANSITION_TO_READY = "to_ready";
+
     #[ORM\Id]
     #[ORM\GeneratedValue]
     #[ORM\Column]
     private ?int $id = null;
 
-    #[ORM\Column(type: Types::TIME_IMMUTABLE, nullable: true)]
+    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
     private ?\DateTimeImmutable $startTime = null;
 
-    #[ORM\Column(type: Types::TIME_IMMUTABLE, nullable: true)]
+    #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)]
     private ?\DateTimeImmutable $endTime = null;
 
     #[ORM\Column(length: 255, nullable: true)]
@@ -39,7 +47,7 @@ class Counter
         return $this->startTime;
     }
 
-    public function setStartTime(\DateTimeImmutable $startTime): static
+    public function setStartTime(?\DateTimeImmutable $startTime): static
     {
         $this->startTime = $startTime;
 
@@ -51,7 +59,7 @@ class Counter
         return $this->endTime;
     }
 
-    public function setEndTime(\DateTimeImmutable $endTime): static
+    public function setEndTime(?\DateTimeImmutable $endTime): static
     {
         $this->endTime = $endTime;
 

+ 55 - 9
src/Service/CounterManager.php

@@ -3,12 +3,22 @@
 namespace App\Service;
 
 use App\Entity\Counter;
+use App\Repository\CounterRepository;
 use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
+use Symfony\Component\HttpKernel\Event\ControllerEvent;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\Workflow\Attribute\AsCompletedListener;
+use Symfony\Component\Workflow\Attribute\AsTransitionListener;
+use Symfony\Component\Workflow\Event\Event;
+use Symfony\Component\Workflow\WorkflowInterface;
 
 class CounterManager
 {
     public function __construct(
-        protected EntityManagerInterface $em
+        protected EntityManagerInterface $em,
+        protected WorkflowInterface $countdownStateMachine,
+        protected CounterRepository $counterRepository
     )
     {
 
@@ -17,24 +27,60 @@ class CounterManager
     public function init(string $ttl, ?string $name = null): Counter
     {
         $counter = new Counter();
-        $counter->setName($name);
-        $counter->setTimeTolive($ttl);
-        $counter->setState('ready');
+        $counter
+            ->setName($name)
+            ->setTimeTolive($ttl)
+        ;
 
+        $this->countdownStateMachine->getMarking($counter);
         $this->em->persist($counter);
         $this->em->flush();
 
         return $counter;
     }
 
-    public function start(Counter $counter): Counter
+    #[AsCompletedListener('countdown', Counter::TRANSITION_TO_STARTED)]
+    public function started(Event $event): void
     {
-        $counter->setStartTime(new \DateTimeImmutable('now'));
-        $counter->setEndTime($counter->getStartTime()->add(new \DateInterval($counter->getTimeTolive())));
+        /** @var Counter $counter */
+        $counter = $event->getSubject();
+        $counter
+            ->setStartTime(new \DateTimeImmutable('now'))
+            ->setEndTime($counter->getStartTime()->add(new \DateInterval($counter->getTimeTolive())))
+        ;
+        $this->em->flush();
+    }
+
+    #[AsCompletedListener('countdown', Counter::TRANSITION_TO_COMPLETED)]
+    public function completed(Event $event): void
+    {
+        return;
+    }
 
-        $counter->setState('started');
+    #[AsCompletedListener('countdown', Counter::TRANSITION_TO_READY)]
+    public function toReady(Event $event): void
+    {
+        /** @var Counter $counter */
+        $counter = $event->getSubject();
+        $counter
+            ->setStartTime(null)
+            ->setEndTime(null)
+        ;
+        $this->em->flush();
+    }
 
+    #[AsEventListener(KernelEvents::CONTROLLER)]
+    public function onKernelController(ControllerEvent $event) {
+        if (!$event->isMainRequest()) {
+            return;
+        }
+
+        $counters = $this->counterRepository->findBy(['state' => Counter::STATE_STARTED]);
+        foreach($counters as $counter) {
+            if ($counter->getEndTime() <= new \DateTime('now')) {
+                $this->countdownStateMachine->apply($counter, Counter::TRANSITION_TO_COMPLETED);
+            }
+        }
         $this->em->flush();
-        return $counter;
     }
 }