0

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

JeremK
  • 11
  • 3
  • Too much code!!! `ServiceMethodCallHandler extends AbstractController` is bizarre but not nearly as bizarre as trying to build a container inside of it's __invoke method. I suspect you might be trying to do things a bit randomly and hoping it works? Start over, create a new project and add the absolute minimum code to demonstrate the issue. You should be able to just inject the entity manager into your handler and have it work. If not then check the code into a repo and post a link. – Cerad Nov 06 '22 at 14:15
  • @Cerad Yes i try so mutch before write this post and i forgot remove extends AbstractController. But i finish by find issue for my problem. Thanks you so mutch your message made me understand that my problem came from an error committed upstream. I build container inside invoke for resolve my first problem, and this build give me another error. I restart to the first and i finish by found issue. Thanks You. – JeremK Nov 07 '22 at 10:43

3 Answers3

0

I found auto-wiring / dependency injection via using aliases always very confusing (what is visible and what is hidden, blahblah), and have usually opted to use default parameter bindings instead:

https://symfony.com/doc/current/service_container.html#binding-arguments-by-name-or-type

Using this method, you would remove the service from the services.yaml entirely (since all parameters will be known) and instead use

services:
    _defaults:
        bind: 
            string $SEND_IN_BLUE_API_KEY: '%env(SEND_IN_BLUE_API_KEY)%'

If in fact the doctrine bundle is missing from your loaded kernel, you have to find a way to add it.

Jakumi
  • 8,043
  • 2
  • 15
  • 32
0

Could you please change this:

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

By this:

    App\Service\SendInBlueService:
        arguments:
            $SEND_IN_BLUE_API_KEY: '%env(SEND_IN_BLUE_API_KEY)%'

As services are autowired.

Skuti
  • 161
  • 1
  • 8
0

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

JeremK
  • 11
  • 3
  • Glad you got something working. Injecting the container is fine for now but is very much frowned upon. Eventually you should take a look at defining a [service locator](https://symfony.com/doc/current/service_container/service_subscribers_locators.html) for your handlers and inject it. Just a question of tagging. – Cerad Nov 07 '22 at 12:33