【问题标题】:Lazy Services via Plugin Manager通过插件管理器提供的惰性服务
【发布时间】:2016-10-13 10:16:38
【问题描述】:

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

插件管理器如下所示。

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__
        ));
    }
}

根据文档;我已将服务“UserService”配置为通过此插件管理器延迟加载。

'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 已注册到 ServiceManager,因此在通过 $entityServiceManager->get('Spectrum\\User\\Entity\\User') 请求服务时无法找到。

错误是:

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

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

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

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

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

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

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

【问题讨论】:

  • @Ocramius ? :-p

标签: php zend-framework2


【解决方案1】:

我猜你必须在插件管理器中手动注册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');
        }
    ],
],

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

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

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

2) 不是依赖插件管理器通过上面的工厂创建LazyServiceFactory,您可以在EntityServiceManager 的工厂中使用setService 方法在创建时注入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 的第一个参数。从那里你可以做和工厂一样的事情。

【讨论】:

  • 当我添加 service manager as a peering service locator 时确实会发生这种情况(这在 2.5.1 版之后已被删除,这将使您的建议成为更好的选择)。现在的问题是validatePlugin() 方法抛出第二个异常,因为LazyServiceFactory 不是EntityServiceInterface 的实例。我看到所有其他插件管理器都执行类似的检查,因此必须有一种方法来正确配置它。
猜你喜欢
  • 2013-11-27
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 2012-05-18
  • 2011-07-05
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多