phpsymfonydependency-injectionsymfony-messenger

Symfony Messenger Injection Doctrine


I need help for my project. I try to inject Entity Manager inside my service (SendInBlueService) call with messenger, but DependencyInjection can't find doctrine.orm.entity_manager.

My test route

#[Route('api/testSendInBlue', name: 'testsendinblue')]
public function testMessenger(AsyncMethodService $asyncMethodService): Response
{
    $asyncMethodService->async_low_priority(
        SendInBlueService::class,
        'confirmationMail',
        [
            $this->getUser()->getId()
        ]
    );

    return new Response('Test OK');
}

My AsyncMethodService

<?php

namespace App\Service\Messenger;

use Symfony\Component\Messenger\MessageBusInterface;

class AsyncMethodService
{
    private MessageBusInterface $messageBus;

    public function __construct(MessageBusInterface $messageBus)
    {
        $this->messageBus = $messageBus;
    }

    public function async_low_priority(string $serviceName, string $methodName,array $params = [])
    {
        $this->messageBus->dispatch(new ServiceMethodCallMessageLowPriority(
            $serviceName,
            $methodName,
            $params
            )
        );
    }
    public function async_medium_priority(string $serviceName, string $methodName,array $params = [])
    {
        $this->messageBus->dispatch(new ServiceMethodCallMessageMediumPriority(
            $serviceName,
            $methodName,
            $params
        )
        );
    }
    public function async_high_priority(string $serviceName, string $methodName,array $params = [])
    {
        $this->messageBus->dispatch(new ServiceMethodCallMessageHighPriority(
            $serviceName,
            $methodName,
            $params
        ));
    }
}

My ServiceMethodCallMessageLowPriority exactly same for High and Medium

<?php

namespace App\Service\Messenger;

class ServiceMethodCallMessageLowPriority extends ServiceMethodCallMessage
{

}

My ServiceMethodCallMessage

<?php

namespace App\Service\Messenger;

class ServiceMethodCallMessage
{
    private string $serviceName;
    private string $methodName;
    private array $params;

    public function __construct(string $serviceName, string $methodName, array $params = [])
    {
        $this->serviceName = $serviceName;
        $this->methodName = $methodName;
        $this->params = $params;
    }

    /**
     * @return string
     */
    public function getServiceName(): string
    {
        return $this->serviceName;
    }

    /**
     * @return string
     */
    public function getMethodName(): string
    {
        return $this->methodName;
    }

    /**
     * @return array
     */
    public function getParams(): array
    {
        return $this->params;
    }
}

My MessengerHandle

<?php

namespace App\Service\Messenger;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

#[AsMessageHandler]
class ServiceMethodCallHandler extends AbstractController
{
    private string $path;

    public function __construct(string $path)
    {
        $this->path = $path;
    }

    public function __invoke(
        ServiceMethodCallMessageLowPriority |
        ServiceMethodCallMessageMediumPriority |
        ServiceMethodCallMessageHighPriority  $message
    )
    {
        $containerBuilder = new ContainerBuilder();
        $loader = new YamlFileLoader($containerBuilder, new FileLocator($this->path));
        $loader->load('services.yaml');

        $callable = [
            $containerBuilder->get($message->getServiceName()),
            $message->getMethodName()
        ];
        call_user_func_array($callable,$message->getParams());
    }
}

My Service Send In Blue

<?php

namespace App\Service;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

class SendInBlueService
{
    private string $SEND_IN_BLUE_API_KEY;
    private EntityManagerInterface $entityManager;

    public function __construct(
        string $SEND_IN_BLUE_API_KEY,
        EntityManagerInterface $entityManager
    )
    {
        $this->SEND_IN_BLUE_API_KEY = $SEND_IN_BLUE_API_KEY;
        $this->entityManager = $entityManager;
    }

    public function confirmationMail(int $userId)
    {
        dd($this->entityManager);
        $user = $this->entityManager->getRepository(User::class)->find($userId);
        dd($user);
    }

}

My config/services.yaml

parameters:
    SEND_IN_BLUE_API_KEY: '%env(SEND_IN_BLUE_API_KEY)%'

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.

    App\:
        resource: '../src/'
        exclude:
            - '../src/Entity/'
            - '../src/Kernel.php'
            - '../src/DependencyInjection/'

    #    Messenger Declaration Service
    App\Service\Messenger\ServiceMethodCallHandler:
        arguments: ['%kernel.project_dir%/config']

    App\Service\SendInBlueService:
        class: App\Service\SendInBlueService
        arguments: ['%env(SEND_IN_BLUE_API_KEY)%','@doctrine.orm.entity_manager']

And for finish my error:

enter image description here

I try get EntityManager with ContainerBuilder inside my service, But i have a same error.

I think i have a problem because messenger use other kernel instance, and inside this instance, the DependencyInjection don't have load all bundles.

If someone has an idea. Thanks you


Solution

  • I found issue,

    My first try on my ServiceMethodCallHandler is :

    <?php
    
    namespace App\Service\Messenger;
    
    use Psr\Container\ContainerInterface;
    use Symfony\Component\Messenger\Attribute\AsMessageHandler;
    
    #[AsMessageHandler]
    class ServiceMethodCallHandler
    {
        public function __construct(ContainerInterface $container)
        {
            $this->container = $container;
        }
    
        public function __invoke(
            ServiceMethodCallMessageLowPriority |
            ServiceMethodCallMessageMediumPriority |
            ServiceMethodCallMessageHighPriority  $message
        )
        {
            $callable = [
                $this->container->get($message->getServiceName()),
                $message->getMethodName()
            ];
            call_user_func_array($callable,$message->getParams());
        }
    }
    

    But ive got error. enter image description here

    I finish by build new container inside __invoke method. This build i can call my service but i create another error. With @Cerad message i understood that it was a mistake to create a new Container inside invoke. I restart to my first error.

    I finish by find issue with add public inside service.yaml

    services:
        # default configuration for services in *this* file
        _defaults:
            autowire: true      # Automatically injects dependencies in your services.
            autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
    
        # makes classes in src/ available to be used as services
        # this creates a service per class whose id is the fully-qualified class name
        App\:
            resource: '../src/'
            exclude:
                - '../src/Entity/'
                - '../src/Kernel.php'
                - '../src/DependencyInjection/'
    
        #    Messenger Declaration Service
        App\Service\Messenger\ServiceMethodCallHandler:
            arguments: ['@service_container']
    
        App\Service\SendInBlueService:
            public: true
            class: App\Service\SendInBlueService
            arguments: ['@doctrine.orm.entity_manager','%env(SEND_IN_BLUE_API_KEY)%']
    

    Thank you all