0

我一直在阅读ZF2服务定位器组件,并可以说我明白它是如何使用的。不过,我有一个问题,我认为它很愚蠢,但不会因为问问题而受伤。ZF2依赖注入到没有服务定位器的控制器对象

我想在我的模块内部有一个名为Component的名称空间,我可以在其中放入泛型代码,比如说FunctionsComponent.php,MailerComponent.php或ExcelComponent.php。这将允许我在控制器内部做一些事情。

我想什么试训是必须有控制器确定他们有兴趣使用组件的能力(见下图):

class SalesController extends AbstractController 
{ 
    protected $components = ['Excel']; 

    //In some action 
    public function exportAction() 
    { 
    $data = ['data to be exported']; 
    /** 
     $data : data to be exported 
     boolean : Whether to force download or save the file in a dedicated location 
    */ 
    $this->Excel->export($data, true); 
    } 
} 

的想法是创建一个可能实现FactoryInterface一个ComponentCollection或ServiceLocatorInterface然后让它检查每个控制器,当MvcEvent已经触发了我的模块类中,并有ComponentCollection注入所有的控制器组件,使他们不使用服务定位器访问,如下图所示:

$excel = $sm->get('Application\Component\Excel'); 

我很清楚,这看起来像是一个令人望而生畏的问题,但我觉得学习框架的最好方法就是玩弄它并尝试做出难以想象的事情。

+0

我不完全确定你在这里问什么。注入控制器依赖关系的最有效方法是通过服务定位器(使用工厂)。否则,Zend中的替代(一个DI容器)将成为'Zend \ Di'组件。他们都解决了同样的问题 - ZF2的偏好应该使用服务定位器。 – AlexP

+0

这个想法是使用框架提供的相同的工具,但不同的是,通过服务定位器来获取特定的组件,而不是通过我们想要在控制器中使用的组件数组来定义组件属性,以及如何制作这些组件可以在后台完成,开发人员可以在每次使用组件时使用$ ComponentName-> functionCall($ parameters),而不是$ component = $ sl-> get('Namespace \ Component \ ActualComponent')。 – Maximum86

+0

您应该避免在您的服务(包括控制器)中使用服务管理器*。你提到的'组件'是类*依赖关系*,意味着它们应该被注入所需的服务(通过服务定位器或DI),因此它们可以作为实例属性(即'$ this-> myService')。如果你希望有一个方便的方法,比如'$ ComponentName-> functionCall($ parameters)',你需要做的就是实现一个'__call()'魔术方法,并确定请求的方法名是否与一个已定义的一流的财产。 – AlexP

回答

1

您应该在某处创建BaseController,然后从BaseController扩展您的所有Controllers。然后你可以在你的BaseController注入你的依赖,并在任何地方使用孩子。例如,我在我Controller这样做是为了套头标题:

<?php 

namespace Application\Controller; 

use Zend\Mvc\Controller\AbstractActionController; 

class BaseController extends AbstractActionController 
{ 

    /** 
    * Sets the head title for every page 
    * 
    * @param string $title 
    */ 
    public function setHeadTitle($title) 
    { 
     $viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager'); 
     // Getting the headTitle helper from the view helper manager 
     $headTitleHelper = $viewHelperManager->get('headTitle'); 

     // Setting a separator string for segments 
     $headTitleHelper->setSeparator(' - '); 

     // Setting the action, controller, module and site name as title segments 
     $siteName = 'Ribbon Cutters'; 
     $translator = $this->getServiceLocator()->get('translator'); 
     $title = $translator->translate($title); 
     $headTitleHelper->append(ucfirst($title)); 
     $headTitleHelper->append($siteName); 
    } 

} 

而是定义方法,你可以定义属性。

public $headTitleHelper 

,并给它分配在BaseController

$this->headTitleHelper = $this->getServiceLocator()->get('ViewHelperManager')->get('headTitle'); 

构造现在你可以在孩子控制器使用$this->headTitleHelper

然后

<?php 

namespace Application\Controller; 

use Zend\View\Model\ViewModel; 
use Application\Controller\BaseController; 

class IndexController extends BaseController 
{ 

    /** 
    * Property for setting entity manager of doctrine 
    */ 
    protected $em; 

    /** 
    * landing page 
    * 
    * @return ViewModel 
    */ 
    public function indexAction() 
    { 

     $this->setHeadTitle('Welcome'); // Welcome - Ribbon Cutters 

     $viewModel = new ViewModel(); 

     return $viewModel; 
    } 



    /** 
    * Sets and gives Doctrine Entity Manager 
    * 
    * @return Doctrine Entity Manager 
    */ 
    protected function getEntityManager() 
    { 
     if (null === $this->em) { 
      $this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default'); 
     } 
     return $this->em; 
    } 
} 

,我认为这可以帮助你。

+0

感谢Bilal我认为我可以在你的解决方案上做些什么或许更多的是插件对象或其他东西。我会让你知道结果.... :-) – Maximum86