通过插件管理器的懒惰服务


Lazy Services via Plugin Manager

我正在尝试通过自定义插件管理器(而不是服务管理器(在 ZF2 中使用惰性服务。

插件管理器如下所示。

use Zend'ServiceManager'AbstractPluginManager;
use Zend'ServiceManager'Exception'RuntimeException;
class EntityServiceManager extends AbstractPluginManager
{
    protected $autoAddInvokableClass = false;
    public function validatePlugin($service)
    {
        if ($service instanceof EntityServiceInterface) {
            return;
        }
        throw new RuntimeException(sprintf(
            'Services created by ''%s'' must be of type ''%s''; ''%s'' provided in ''%s''.',
            get_called_class(),
            'EntityServiceInterface',
            (is_object($service) ? get_class($service) : gettype($service)),
            __METHOD__
        ));
    }
}

根据文档;我已经将服务"用户服务"配置为通过此插件管理器延迟加载。

'service_manager' => [
    'factories' => [
        'Zend''ServiceManager''Proxy''LazyServiceFactory'
            => 'Zend''ServiceManager''Proxy''LazyServiceFactoryFactory',
    ],
],
'lazy_services' => [
    'class_map' => [
        'User''Entity''User' => 'User''Service''UserService',
    ],
],
'entity_service_manager' => [
    'delegators' => [
        'User''Entity''User' => [
            'Zend''ServiceManager''Proxy''LazyServiceFactory',
        ],
    ],
    'factories' => [
        'User''Entity''User' => 'User''Factory''Service''UserServiceFactory'
    ],
],

问题是LazyServiceFactory已注册到服务管理器,因此在通过 $entityServiceManager->get('Spectrum''User''Entity''User') 请求服务时找不到。

错误是:

可捕获的致命错误:参数 1 传递给 Zend''ServiceManager''Proxy''LazyServiceFactory::__construct(( 必须是 ProxyManager''Factory''LazyLoadValueHolderFactory 的实例,没有给出

这是因为插件管理器会将工厂创建为可调用的,而不是通过注册的LazyServiceFactoryFactory

我尝试为插件管理器提供一个对等管理器,以允许它通过"父"服务管理器找到工厂。

`$entityServiceManager->addPeeringServiceManager($serviceManager);`

这允许找到工厂,但它无法在validatePlugin()方法中进行验证。

Zend''ServiceManager''Exception''RuntimeException",消息"由'EntityServiceManager'创建的服务"的类型必须是'EntityServiceInterface';'Zend''ServiceManager''Proxy''LazyServiceFactory' 在 'EntityServiceManager::validatePlugin' 中提供。

如何向插件管理器注册惰性服务?

我想

您必须在插件管理器中手动注册LazyServiceFactory,并为其提供一个自定义工厂,该工厂确实从插件管理器的父服务定位器中获取它:

'entity_service_manager' => [
    'delegators' => [
        'User''Entity''User' => [
            'Zend''ServiceManager''Proxy''LazyServiceFactory',
        ],
    ],
    'factories' => [
        'User''Entity''User' => 'User''Factory''Service''UserServiceFactory',
        'Zend''ServiceManager''Proxy''LazyServiceFactory' => function ($pluginManager) {
            return $pluginManager->getServiceLocator()->get('Zend''ServiceManager''Proxy''LazyServiceFactory');
        }
    ],
],

未经测试,但应该给你这个想法。需要从父服务定位器获取实例的方法,以避免工厂的双重实例化(一次用于全局服务管理器,一次用于插件管理器(。

更新正如评论中指出的,插件管理器不允许创建LazyServiceFactory。我可以想到两种方法:

1(没有什么说validatePlugin方法只能检查并通过一个插件。当您自己实现 validatePlugin 方法时,也可以允许创建LazyServiceFactory。严格来说,这可能不是最好的方法,因为插件管理器应该坚持返回一个接口。

2(与其像上面那样依靠插件管理器通过工厂创建LazyServiceFactory,不如使用setService方法在EntityServiceManager工厂中创建时注入LazyServiceFactory的实例:

class YourPluginManagerFactory extends AbstractPluginManagerFactory
{
    const PLUGIN_MANAGER_CLASS = 'EntityServiceManager';
    public function __invoke(ContainerInterface $container, $name, array $options = null)
    {
        $instance = parent::__invoke($container, $name, $options);
        $lazyFactory = $container->get(LazyServiceFactory::class);
        $instance->setService(LazyServiceFactory::class, $lazyFactory);
    }
}

应该绕过validatePlugin方法的检查。

3(最后一个想法,虽然不符合依赖注入,但你的插件管理器接收父服务管理器的实例作为constructor的第一个参数。从那里您可以像工厂一样做同样的事情。