Factory and dynamic dependency

Hello everyone,
I have a restful resource that fetch common anagraphics data from a table, and provides additional information based on them by calling the specified service in the table (In a fqdn form):

name surname service
John Doe \app\serviceA
Jane Doe \app\serviceB

Those service share a common interface, have their own factories and configurations, and provides different clients for different requests under common interface names.

Because of their dependencies, I can’t instantiate them on the fly and I need to preload all of them inside the resource factory.

I was wondering if there’s a way, like a middleware or an event, to dynamically load only the specific adapter needed and not all of them from the resource factory.

class MyResourceFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null): MyResource
    {
        $model = $container->get("MyModel");
        
        $adapter = null;
        if($id = $container->get("Request")->getQuery("id"))
        {
            if($adapter = $model->getById($id))
            {
                $adapter = $container->get( $adapter[0]->getAdapter() );
            }
        }

        return new MyResource($adapter);
    }
}

Just for test I’m ended up with this “solution” but I think it’s not the right way…

Hello and welcome to our forums! :smiley:

The information that there is an HTTP request at all should not be brought to other layers. Only controllers or request handlers should be aware of this.

A custom plugin manager might be suitable for your use case:

1 Like

Hello froschdesign!
Thanks for your response!

I think the plugin manager should do the trick! (I haven’t noticed it before… :sweat_smile: )

Hoping that I understand the point, I came up with this solution:
A dedicate module configuration like this in my Module.php:

class Module implements ServiceProviderInterface
{
    public function getServiceConfig(): array
    {
        return [
            'factories' => [
                \App\serviceA::class => \App\serviceAFactory::class,
                \App\serviceB::class => \App\serviceBFactory::class,
                
                \App\MyPluginManager::class => function(ContainerInterface $container, $requestedName) {
                        return new \App\MyPluginManager($container, [
                            'factories' => [
                                \App\serviceA::class => \App\serviceAFactory::class,
                                \App\serviceB::class => \App\serviceBFactory::class,
                            ],
                        ]);
                    },
            ];
    }
}

A part from the repeated statements of factories, I can include the plugin manager inside the resource though the factory:

class MyResourceFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null): MyResource
    {
        $model = $container->get("MyModel");
        $pluginManager = $container->get(\App\MyPluginManager::class);

        return new MyResource($model, $pluginManager);
    }
}

And later use it inside the resource to fetch the specific adapter

class MyResource extends AbstractRestfulController
{
    private \App\MyModel $model;
    private \Laminas\ServiceManager\PluginManagerInterface $pluginManager;

    public function __construct(\App\MyModel $model,
                                \Laminas\ServiceManager\PluginManagerInterface $pluginManager)
    {
        $this->model = $model;
        $this->pluginManager = $pluginManager;
    }
    
    public function get(mixed $id)
    {
        if($id = $model->getById($id))
        {
            $adapter = $this->pluginManager->get( $adapter[0]->getAdapter() );
        }
        
        [...]

Do you think this is a good way to approach the issue or it can be do better?
Thanks again for your response :slight_smile: