Roave / psr-container-doctrine

Doctrine Factories for PSR-11 Containers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Multiple EntityManagers wont work due to invalid AbstractFactory

boesing opened this issue · comments

Hey there,

I tried to use this package with multiple EntityManager instances.
I realized that the EntityManagerFactory does not pass the requestedName to the factory and thus its always orm_default which is being created:

from laminas-servicemanager

if (is_string($factory) && class_exists($factory)) {
    $factory = new $factory();
    $lazyLoaded = true;
}

from AbstractFactory in this project

  /** @internal */
public function __construct(string $configKey = 'orm_default')
{
    $this->configKey = $configKey;
}

/**
 * @return mixed
 */
public function __invoke(ContainerInterface $container)
{
    return $this->createWithConfig($container, $this->configKey);
}

$requestedName is never passed the __construct consumed by __invoke.

Did I overlooked something or is this a bug?

$requestedName is (afaik) specific to Laminas ServiceManager, so I don't think it's something we can use here.

It's been a while since I looked at that, but I think the intention is to do something like:

$container = new ServiceManager([
    'factories' => [
        'doctrine.entity_manager.orm_default' => EntityManagerFactory::class,
        'doctrine.entity_manager.a_different_entity_manager' => [EntityManagerFactory::class, 'a_different_entity_manager'],
    ],
]);

Uhm, using arrays in the factories is not what I expected to use as it has to be a callable.

So I think I have to create an EntityManagerAbstractFactory for laminas-servicemanager and create the EntityManagerFactory in that factory.

The [EntityManagerFactory::class, 'a_different_entity_manager'] is a callable; since EntityManagerFactory extends AbstractFactory, that callable will invoke \Roave\PsrContainerDoctrine\AbstractFactory::__callStatic exists so this can be done in a Container-implementation-agnostic way; the $name param (in the example, a_different_entity_manager) is passed to a new instance of EntityManagerFactory constructor, and then the __invoke method is called. I'm fairly sure that is designed specifically so does what you want it to do, but if you really don't want an array-style callable for your factory definition, it's fine to do your own thing too :)

Note; whilst the documentation is indeed lacking, the example configuration shows what you're trying to do, if I understand the issue correctly:

$container = new ServiceManager([
'factories' => [
'doctrine.entity_manager.orm_other' => [EntityManagerFactory::class, 'orm_other'],
],
]);

Oh I see, there is a __callStatic magic method for that. Wasn't aware of that. 👍
Gonna have a look on this.
Thanks for the feedback!

<insert "magic" gif here> 😆