Bonjour à toutes et à tous,
Ceci est mon premier message sur ce forum, je ne connais pas trop la netiquette à respecter, j'espère ne pas faire d'impair.

J'utilise Symphony 7.0 avec php 8.3.1

j'ai besoin de coder un traitement qui s'éxécutera tous les jours et qui doit interragir avec la base de données.
Pour gérer la récurrence, j'utilise le ScheduleProviderInterface. Pas de soucis sur ce point, mon traitement se déclenche bien comme je le souhaite.
En revanche, dans ce traitement, je dois pouvoir utiliser un EntityManager afin de chercher, créer et modifier des données.

Le code du scheduler (10 second c'est juste pour les tests ;-)

#[AsSchedule(name: 'default')]
class SchedulerProvider implements ScheduleProviderInterface
{
    public function getSchedule(): Schedule
    {
        $schedule=(new Schedule())
        ->add(RecurringMessage::every('10 second', new GenerateRecurringEntry()));
        return ($schedule);
    }
}

Le code de la classe schédulée

#[AsMessageHandler]
readonly final class  GenerateRecurringEntry
{
    public function __invoke(GenerateRecurringEntry $generateRecurringEntry): void
    {
   //Ici, si j'avais un EntityManager, je pourrais faire 
        $recurringEntryRepository = $em->getRepository(RecurringEntry::class);
        $recurringEntries = $recurringEntryRepository->findAll();
        foreach ($recurringEntries as $recurringEntry) {
            $accountEntry = new AccountEntry;
            $accountEntry->setAccount($recurringEntry->getAccount());
//            ...
            $em->persist($accountEntry);
        }
    }
}

Donc en gros mon soucis est que je ne vois pas comment obtenir cet EntityManager ; Je ne suis pas dans un abstractController, je ne vois pas comment l'injecter.

5 réponses


Grafikart
Réponse acceptée

Normalement tu es sensé avoir 2 classes, une classe qui représente le message et une qui représente le "handler" non ? Avec l'EntityManager injecté au niveau de l'handler.

Tu l'injecte dans le constructeur de ta classe, symfony l'injectera automatiquement

public function __construct (private readonly EntityManagerInterface $em) {

}

Tu as ce tutoriel qui explique le principe

Didier G
Auteur

Bonjour et merci pour ta réponse,
C'est ce que je pensais et j'avais déjà testé cette approche, , mais j'ai une erreur
In RecurringMessage.php line 86:
[Exception]
Serialization of 'Closure' is not allowed
Exception trace:
at /Users/.../MonProjet/vendor/symfony/scheduler/RecurringMessage.php:86
serialize() at /Users/didiergibot/Documents/Informatique/Projets/MesComptes/vendor/symfony/scheduler/RecurringMessage.php:86

J'ai mis le constructeur dans ma class Scheduler

#[AsSchedule(name: 'default')]
class SchedulerProvider implements ScheduleProviderInterface
{

    public function __construct (private readonly EntityManagerInterface $em) {}

    public function getSchedule(): Schedule
    {
        $schedule=(new Schedule())
        ->add(RecurringMessage::every('2 second', new GenerateRecurringEntry($this->em)));
         return ($schedule);
    }
}

et également dans la classe GenerateRecurringEntry. La l'EM est passé au constructeur via le Sceduller

#[AsMessageHandler]
readonly final class  GenerateRecurringEntry
{
    public function __construct (private readonly EntityManagerInterface $em) {}

    public function __invoke(GenerateRecurringEntry $generateRecurringEntry): void
    {

        $recurringEntryRepository = $this->em->getRepository(RecurringEntry::class);
        ...
     }
}    
Didier G
Auteur

Oui en effet, je me suis fait avoir car sur ma première implémention d'un test de tâche schédulée, je n'avais que le handler et ça fonctionnait. Mais je n'avais rien à injecter.
Ca fonctionne désormais avec les deux classes.

Il semble y avoir un problème avec la sérialisation d'une fermeture dans votre code. Cela peut se produire si la fermeture utilise des variables provenant d'un contexte ici externe qui ne peut pas être sérialisé.

Didier G
Auteur

Oui, mais en utilisant 2 classes, une pour le message et une pour le handler en injectant l'EntityManager au niveau du handler, comme Grafikart l'a fort justement proposé, , ça fonctionne parfaitement.