elie29/zend-di-config

Compile with Delegators

Closed this issue · 3 comments

Is your feature request related to a problem? Please describe.
When a delegator is in use, the container can not be compiled:
PHP Fatal error: Uncaught DI\\Definition\\Exception\ \InvalidDefinition: Cannot compile closures which import variables using the use keyword in.... When disabling the used delegator, it works.

Describe the solution you'd like
Even when using delegators, it would be fantastic for performance to be able to compile/cache it, the closure with use crashes the caching.
Hints on what can be used otherwise would help also a lot! (Or if i'm again using something in the wrong part)
Moving the routes in a central definition is not wanted in the architecture.

Additional context
I'm using the ApplicationConfigInjectionDelegator to be able to have the route definitions in the corresponding module ConfigProvider, like explained here.

public function getDependencies(): array {
    return [
        'delegators' => [
            \Mezzio\Application::class => [
                \Mezzio\Container\ApplicationConfigInjectionDelegator::class,
            ],
        ],
    ];
}

Thanks!
michael

@elbakerino thank you for the issue.

As delegators are assigned by a closure, the fatal error came from PHP-DI as follow:
Fatal error: Uncaught DI\Definition\Exception\InvalidDefinition: Cannot compile closures which import variables using the use keyword in vendor\php-di\php-di\src\Compiler\Compiler.php on line 391

However, in order to preserve previous service and delegators, we cannot bypass the 'use' keyword.

You can add a factory that return \Mezzio\Application if you want to use the cache:

class MyApplicationFactory
{

    public function __invoke(ContainerInterface $container): \Mezzio\Application
    {
        $factory = new \Mezzio\Container\ApplicationConfigInjectionDelegator();
        $callable = function () use ($container) {
            return $container->get(\Mezzio\Application:class);
        };
        return $factory($container, \Mezzio\Application:class, $callable);
    }
}

And then in your ConfigProvider, you add the following:

public function getDependencies(): array {
    return [
        'factories' => [
            \Mezzio\Application::class => MyApplicationFactory::class,
        ],
    ];
}

Thanks for you help!

Adding it leaded to Circular dependency detected while trying to resolve entry 'Mezzio\\Application', should come from getting the Application from the container inside the factory that defines it.

For me it worked with using the \Mezzio\Container\ApplicationFactory inside:

class MyApplicationFactory {
    public function __invoke(ContainerInterface $container): \Mezzio\Application {
        $factory = new \Mezzio\Container\ApplicationConfigInjectionDelegator();
        $callable = static function() use ($container) {
            $app_factory = $container->get(\Mezzio\Container\ApplicationFactory::class);
            return $app_factory($container);
        };
        return $factory($container, \Mezzio\Application::class, $callable);
    }
}

@elbakerino exactly. My code was just an example to help you. I did not test it.