在模型中获取服务

Get a service inside a model

我是 zend 2 的新手,我想实现几个模型,这些模型可以从 我想要的任何地方 访问,即从控制器和其他模型访问。

从控制器它已经可以工作了。但是我不知道如何在没有 getServiceLocator() 方法的模型中进行操作。此外,我无法从模型内部访问服务定位器来获取配置。

namespace Bsz\Services;
use Zend\ServiceManager\ServiceLocatorAwareInterface;

class OpenUrl implements ServiceLocatorAwareInterface {

    protected $serviceLocator;

    public function __construct() {
        $sm = $this->getServiceLocator();
        $config = $sm->get('config');
        var_dump($sm); //null
    }    
    public function setServiceLocator(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator)
    {
        $this->serviceLocator = $serviceLocator;
    }
    public function getServiceLocator()
    {
        return $this->serviceLocator;
    }
}

来自 module.config.php

的片段
'service_manager' => [
    'invokables' => [
        'bsz\openurl' => 'Bsz\Services\OpenUrl',
    ]
],

这里是我的 Action,它已经有效了

public function indexAction() {

   $OpenUrl = $this->getServiceLocator()->get('bsz\openurl');
   //works, is an object of type bsz\openurl. 
}

所以我的问题是:如何在本身用作服务的模型中正确地获取服务管理器?如何在其他模型中执行此操作?

我发现了很多这样的问题并尝试了很多,但仍然没有解决这个问题。也许 Zend 的版本差异? 我们使用 Zend 2.3.7

我现在找到了第一个问题的答案:必须将 erviceManager 注入到模型中。这只能通过工厂来完成:

Factory.php

namespace Bsz\Services;
use Zend\ServiceManager\ServiceManager;

class Factory {

    public static function getOpenUrl(ServiceManager $sm)
    {        
        return new \Bsz\Services\OpenUrl($sm);
    }
}

module.config.php

 'service_manager' => [
    'factories' => [
        'bsz\openurl' => 'Bsz\Services\Factory::getOpenUrl',            
    ]
],

但是如何从另一个没有 getServiceLocator 方法的模型中检索此服务?

OpenUrl 服务 取决于 它的配置。因此,配置是服务的 dependency。在没有配置的情况下创建服务是没有意义的。

您已将 bsz\openurl 服务注册为 'invokable' class。这意味着当您请求服务时,服务管理器将实例化 Bsz\Services\OpenUrl class 而无需传入任何构造函数参数。这不是您想要的,您 需要 创建 class 后的配置。

向服务工厂注册服务

The factory [method] pattern is a creational pattern which uses factory methods to deal with the problem of creating objects.

为了实现这个 ZF2 附带了它自己的工厂接口,Zend\ServiceManager\FactoryInterface,我们的新工厂应该实现它。

namespace Bsz\Services;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class OpenUrlFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $config  = $this->getConfig($serviceLocator);
        $service = new OpenUrl($config);

        return $service;
    }

    protected function getConfig(ServiceLocatorInterface $serviceLocator)
    {
        $config = $serviceLocator->get('config');

        if (! isset($config['open_url'])) {
            throw new \RuntimeException('The service configuration key \'open_url\' could not be found');
        }
        return $config['open_url'];
    }
}

现在我们可以更新 module.config.php 并将服务类型更改为工厂。

'service_manager' => [
    'factories' => [
        'bsz\openurl' => 'Bsz\Services\OpenUrlFactory',
    ],
],

在此之后,如果 SomeService depends on OpenUrl 那么您可以使用新的 SomeServiceFactory 重复工厂过程,其中依赖项是 OpenUrl.