Zend 2最佳实践 - 控制器外侧的服务定位器

时间:2014-02-26 18:36:45

标签: php zend-framework zend-framework2

我是Zend 2的新手并且有这种情况。想知道处理这种情况的最佳方法。

在Application模块中我有这些类

namespace Application\Foo;

class Base {
    protected $this->services; //service locator
    public function myFunc() {
        //needs service locator here
        $this->services;
    }
}

namespace Application\Foo;

class A extends Base {
    //can have some method that uses $this->services;
}

namespace Application\Foo;

class B extends Base {

}

正如您所看到的,我需要Base类中的服务定位器。然后我想在我的控制器中使用A,B ......扩展类。

感谢您的建议


更新

根据jmleroux的建议,我更新了代码,看起来像这样

namespace Application\Foo;

use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class Base implements ServiceLocatorAwareInterface {
    protected $this->services; //service locator

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
        $this->services = $serviceLocator;
    }

    public function getServiceLocator() {
        return $this->services;
    }


    public function myFunc() {
        //needs service locator here
        $this->services;
    }
}

module.conf.php

service_manager => array(
    'invokables' => array(
        'my_ser' => 'Application\Foo\Base'
    )
)

在我的控制器中

$this->serviceLocator->get('my_ser'); 

返回加载了服务定位器的基类

现在我的问题是如何在加载服务定位器的情况下获取扩展类(A,B ...)。从那以后

$x = new \Application\Foo\A(); 

没有加载服务定位器。我是否必须将所有扩展类添加到模块配置中作为 invokables ?还是有更好的选择。

再次感谢。


更新2

感谢所有人(特别是@jmleroux)的支持。找到这些解决方案,我在这里添加它们认为它将帮助其他人

注意:只是一个大致的想法。名称空间和类名称不准确

解决方案1(推荐) - 使用ServiceLocatorAwareInterface / ServiceLocatorAwareTrait for php 5.4 +

每个类实现ServiceLocatorAwareInterface并将其添加到服务管理器

namespace Application\Foor;

class A implements ServiceLocatorAwareInterface {
protected $services;

public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
    $this->services = $serviceLocator;
}

public function getServiceLocator() {
        return $this->services;
    }
}

class B implements ServiceLocatorAwareInterface {
    use ServiceLocatorAwareTrait;
}

module.conf.php(或在模块getServiceConfig()函数内部)

'service_manager' => array(
    'invokables' => array(
        'my_ser_a' => 'Application\Foo\A',
        'my_ser_b' => 'Application\Foo\B',
        ......
    )
)

在控制器内按名称调用服务


解决方案2 - 使用AbstractFactoryInterface

创建工厂类

class MyFac implements AbstractFactoryInterface {
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        if (class_exists($requestedName)){ \\eg. check Application\Foo\A exists
            return true;
        }

        return false;
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName) {
        $class = new $requestedName;   \\eg. creates an instance of Application\Foo\A
        $class->setServiceLocator($locator); \\make sure your class has this method 
        return new $class;
    }
}

module.conf.php(或在模块getServiceConfig()函数内部)

'service_manager' => array(
    'abstract_factories' => array(
        'Application\Foo\MyFac'
    )
)

在控制器中调用

$this->getServiceLocator()->get('Application\Foo\A');

感谢。

1 个答案:

答案 0 :(得分:2)

为了访问服务定位器,您的基类需要声明为实现ServiceLocatorAwareInterface.php的可调用服务

如果您使用的是PHP 5.4+,则可以使用ServiceLocatorAwareTrait.php