【问题标题】:Zend Framework 2 Service Manager Dependency InjectionZend Framework 2 服务管理器依赖注入
【发布时间】:2014-03-15 02:05:18
【问题描述】:

我的应用程序是 POPO 的集合,我正在尝试使用 Zend Framework 2 服务管理器连接这些 POPO。

为了说明我的问题,举个例子:

$config = array(
   'services' => array(
      'my.app.serviceA' => new \My\App\Services\ServiceA(),
      'my.app.serviceB' => new \My\App\Services\ServiceB(),

      'my.app.manager.task' => new \My\App\Manager\TaskManager(),
   ),

);

我的 TaskManager 类看起来像这样:

class TaskManager {

   protected $serviceA;
   protected $serviceB;

   public function setServiceA( \My\App\Service\ServiceA $serviceA )
   {
      $this->serviceA = $serviceA;
   }

   public function setServiceB( \My\App\Service\ServiceB $serviceB )
   {
      $this->serviceB = $serviceB;
   }

}

如您所见,TaskManager 类同时依赖于ServiceAServiceB。如何使用为ServiceAServiceB 定义的服务名称使用服务管理器配置将这些服务注入my.app.manager.task

更新:

我开始相信我根本不应该将 ServiceManager 组件用于我的目的,而应该使用 Zend DI 组件。

我的印象是 ServiceManager 是一个 ZF2“框架”组件,而 Zend\DI 似乎更像是一个通用的通用 DiC。因此,这可能是 ServiceManager 与 MVC 和 ModuleManager 组件(它们似乎也是“框架”组件)绑定关系的原因。

也许有人可以澄清一下?

【问题讨论】:

    标签: dependency-injection zend-framework2 servicemanager


    【解决方案1】:

    在 module.config.php 中服务管理器可以通过 7 种不同的方式进行配置:

    return array(
    
        // instantiate the class for you when needed
        'invokables' => array(
            'commentController' => '\Comment\Controller\CommentController';
        ),
    
        // Aliasing a name to a known service name
        'aliases' => array(
            'Comment\Service' => 'commentService';
        ),
    
        // configure the instance of the object
        'factories' => array(
            'commentController' => function ($sm) {
                $locator = $sm->getServiceLocator();
                $controller = $locator->get('commentController');
                $controller->setCommentService($locator->get('Comment\Service'));
                return $controller;
            }
        ),
    
        // register already instantiated objects
        'services' => array(
            'commentController' => new \Comment\Controller\CommentController(),
        ),
    
        //factory instance that can create multiple services based on the name supplied to the factory.
        'abstract_factories' => array(
            'SomeModule\Service\FallbackFactory',
        ),
    
        // initialize the service whenever service created
        'initializers' => array(
            function ($instance, $sm) {
                if ($instance instanceof \Comment\Controller\CommentController){
                    $instance->setCommentService($sm->get('Comment\Service'));
                }
            }
        ),
    
        // indicating whether or not a service should be shared
        'shared' => array(
            'commentController' => false,
        ),
    );
    

    在 Module.php 中

    public function getControllerConfig() {
        return array(
            'factories' => array(
                'commentController' => function ($sm) {
                    $controller = new \Comment\Controller\CommentController();
                    $locator = $sm->getServiceLocator();
                    $controller->setCommentForm($locator->get('commentForm'));
                    $controller->setCommentService($locator->get('commentService'));
                    return $controller;
                }
            )
        );
    }
    

    在控制器中的简单使用:

     $commentService = $this->serviceLocator->get('Comment\Service');
    

    你把它放在 getter 或 init() 方法中 ZF2's New Controller::init() :: phly, boy, phly

    【讨论】:

    • 我理解这一点,工厂不是解决方案(在我看来)。问题是;如何设置配置以便我可以描述一个服务,然后将该服务注入另一个服务。你喜欢,Spring 框架 bean 的接线是如何工作的?
    • 在 zend 中,我没有看到任何链接 bean-appcontext.xml 但可能存在,但是您可以在每个拥有 serviceLocator 的地方访问您的服务。
    • 如果你想为每个用例使用不同的文件,你可以在同一个地方定义所有用例的bean。您可以在工厂加载文件 include DIR 。 '/config/usecase-appcontext.php' 但 PHP 不是 J2EE。
    • 阿明。我感谢您的意见,但这无济于事。 Spring bean 引用只是我所追求的“技术”的一个示例。我想定义一个服务,然后将该服务定义注入另一个服务。
    • 我认为你可以使用它:github.com/fezfez/ServiceLocatorFactory。但是在您访问服务定位器的任何地方,您都可以访问已注册的服务,并且您可以在任何地方访问服务定位器。
    【解决方案2】:

    在控制器中;

    $yourService = $this->getServiceLocator()->get('your_service_alias');
    

    在查看助手中: 您应该通过 viewHelper 的构造函数从 Module.php 发送

        public function getViewHelperConfig() {
            return array(
                'factories' => array(
                    'loginHelper' => function($sm) {
                        return new LoginHelper($sm);
                    }
            )
       }
    

    在课堂上

    use Zend\ServiceManager\ServiceLocatorAwareInterface;
    use Zend\ServiceManager\ServiceLocatorInterface;
        public class UseCaseBO implements ServiceLocatorAwareInterface {
          protected $serviceLocator;
    
          public function setServiceLocator(ServiceLocatorInterface $serviceLocator) {
            $this->serviceLocator = $serviceLocator;
          }
    
          public function getServiceLocator() {
            return $this->serviceLocator;
          }
    
          // now instance of Service Locator is ready to use
          public function someMethod() {
            $table = $this->serviceLocator->get('your_service_alias');
            //...
          }
        }
    

    【讨论】:

    • 阿明。再次感谢您的意见,但您似乎不理解这个问题。请停止发布答案。
    【解决方案3】:

    对我来说,最好的方法是创建一个类工厂并使用 factoryInterface,如下所示:

     return array(
    
        'service_manager' => array(
            'factories' => [
                'Task' => 'Application\TaskFactory',
            ],
            'invokables' => array(
                'Task'=> 'Application\Task',
                'ServiceA'=> 'Application\ServiceA',
                'ServiceB' => 'Application\ServiceB'
            )
        ),
    );
    

    还有一个工厂类:

    class TaskFactory implements FactoryInterface {
    
        /** @var  ServiceLocatorInterface $serviceLocator */
        var $serviceLocator;
    
        public function createService(ServiceLocatorInterface $serviceLocator) {
            $sl = $this->serviceLocator = $serviceLocator;
    
            // you can get your registered services
            $serviceA = $sl->get('ServiceA');
            $serviceB = $sl->get('ServiceB');
    
    
            // You can build your class using the class loader
            $task = new Application\Task();
    
            // Or the Service Locator Again
            $task = $sl->get('Task');
    
            return $task;
        }
    }
    

    您可以在 Task 类上实现工厂接口。我更喜欢控制我正在构建的内容。

    【讨论】:

    • 对不起。问题根本不是关于工厂的,而是关于配置服务管理器以允许它将一个服务定义注入另一个服务定义。
    猜你喜欢
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多