Question

AbstractPluginManager has an interesting property called $autoAddInvokableClass which, when enabled, automatically adds any class you attempt to invoke to its list of invokables. Unfortunately, as far as I know, this behaviour is not implemented by ServiceManager itself.

What would be the best way to implement this behaviour in the Application's ServiceManager such that $applicationServiceManager->get(SomeUnregisteredClass::class) would load SomeUnregisteredClass even without registering it with $applicationServiceManager and therefore still run any relevant initializers on the object?

Attempting to do this without registering SomeUnregisteredClass normally throws an exception similar to the following.

Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for SomeUnregisteredClass

Was it helpful?

Solution

First, please realise all the possibilities you create with this feature: do you really need this?

Then, the "root" service manager does not have a autoAddInvokableClass property. You can, however, create your own service manager and register that as the default one.

Create your custom one:

<?php
namespace MyLib\ServiceManager;

use Zend\ServiceManager as BaseServiceManager;

class ServiceManager extends BaseServiceManager
{
    protected $autoAddInvokableClass = true;

    public function get($name, $options = array(), $usePeeringServiceManagers = true)
    {
        // Allow specifying a class name directly; registers as an invokable class
        if (!$this->has($name) && $this->autoAddInvokableClass && class_exists($name)) {
            $this->setInvokableClass($name, $name);
        }

        return parent::get($name, $options, $usePeeringServiceManagers);
    }
}

Mind that ALL service managers will extend from this one, including the controllers loader. So if you have a route /foo/:controller[/:action] you can load ANY class this way as you specify a FQCN in the :controller parameter!

Anyhow, that being said, just enable this SM in your application config:

<?php
return array(
    'modules' => array(
        'Application',
        // Your module here
    ),

    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
    ),

    // Used to create an own service manager. May contain one or more child arrays.
    'service_listener_options' => array(
        array(
            'service_manager' => 'MyLib\ServiceManager\ServiceManager',
        ),
    ),
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top