2012-10-21 56 views
5

我的問題簡而言之:我可以爲多個控制器使用單個工廠嗎?單個工廠的多個控制器?

更多細節:

我在/config/autoload/global.php一些全球性的非特定模塊設置,這些設置是這樣的:

return array(
    'settings' => array(
     'setting_a' => 'foo', 
     'setting_b' => 'bar' 
    ), 

    // More ZF default configuration ... 
); 

現在我要進行這些設置每個控制器都可訪問,無需一直致電$this->getServiceLocator()->get('config')

所以我的想法是在我的AbstractController中引入一個類屬性$settings,它被注入配置數組。我試圖直接在AbstractController的構造函數中獲取配置。但是,getServiceLocator()似乎沒有準備好,並返回NULL。

我可以建立每個控制器控制器工廠,注入這樣的設置:

class ControllerFactory implements FactoryInterface 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) { 
     $config = $serviceLocator->get('config'); 
     return new \MyModule\Controller\MyController($config['settings']); 
    } 
} 

但是,這將是相同的一遍又一遍。所以我的問題是:我可以使用單個工廠的多個控制器?

在我module.config.php我能爲多個控制器指定單個工廠類:

return array(
    'controllers' => array(
     'factories' => array(
      'MyModule\Controller\MyControllerA' => 'MyModule\Factory\ControllerFactory', 
      'MyModule\Controller\MyControllerB' => 'MyModule\Factory\ControllerFactory', 
      'MyModule\Controller\MyControllerC' => 'MyModule\Factory\ControllerFactory', 
     ) 
    ), 
); 

但在工廠我需要手工恢復實際控制對象(見上面的例子)這當然只適用於每個控制器一個工廠。

希望我明確了我的問題。

更新2013年3月24日:

雖然我第一次,然後創建一個初始建議的解決方案,我從來沒有真正使用它只是爲配置的注入喜歡。

所以我一直在挖掘並最終創建一個Controller插件來接收設置。

該插件的代碼如下所示:

use Zend\Mvc\Controller\Plugin\AbstractPlugin; 

class Settings extends AbstractPlugin 
{ 
    protected $settings; 

    public function __invoke() 
    { 
     $config = $this->getController()->getServiceLocator()->get('Config'); 

     if (isset($config['settings']) && is_array($config['settings'])) { 
      $this->settings = $config['settings']; 
     } 

     return $this->settings; 
    } 
} 

'controller_plugins' => array(
    'invokables' => array(
     'settings' => 'My\Controller\Plugin\Settings', 
    ) 
), 

添加插件在module.config.php後,我可以在控制器內方便地訪問我的設置只需撥打$this->settings()即可。希望這有助於任何人。

回答

6

您可以嘗試附加初始化程序,然後在創建控制器時,會根據已知的初始化程序檢查實例。如果實例匹配給定的接口或抽象類,那麼你可以應用一些通用的邏輯。

我還沒有用控制器測試過這種方法,但是鑑於ControllerLoader是一種ServiceManager/ServiceLocator,它應該在理論上起作用。

'controllers' => array (
    'initializers' => array(
     'MyApplication\Controller\Initializer' 
    ) 
), 

然後Initalizer看起來是這樣的:

class Initializer implements InitializerInterface 
{ 
    public function initialize($instance, ServiceLocatorInterface $serviceLocator) 
    { 
     if (!$instance instanceof MyControllerInterface) 
     { 
      return; 
     } 

     // Do something for this instance 
    } 
} 
+0

感謝您的想法。初始化器本身就像你描述的那樣工作,但是一旦我將它添加到'controllers'數組中,控制器映射不知何故會丟失,並且我得到一個錯誤,說*「請求的控制器不能映射到現有的控制器類。」*它似乎'控制器'內的'invokables'和'initializers'互相咬人。你有什麼建議嗎? – Rob

+0

我會倒回到只是invokables然後應用初始化程序 - 然後調試如果初始化程序正在獲取實例。拋出的錯誤信息可能有多種原因,請確保所有使用的定義都是正確的,並且沒有錯誤。爲了深入挖掘,我還會看看\ Zend \ Mvc \ Service \ ControllerLoaderFactory.php並將其貫穿到\ Zend \ Mvc \ Controller \ ControllerManager.php - 我希望能夠幫到您。 – DrBeza

+0

找到原因:它是初始化程序:: initialize()中的$ serviceLocator-> get('Config')'調用,它引發*服務未找到異常*。所以看起來配置在初始化階段還沒有準備好。我仍然無法將我的設置到控制器中:-(現在嘗試一種解決方法 – Rob

1

不知道你是怎麼做以後的更新 「更新2013年3月24日」;)

你爲什麼不只是請使用您建議的控制器,但要將所有控制器中需要的代碼放入您從中繼承的抽象工廠,例如:

abstract class AbstractControllerFactory implements FactoryInterface 
{ 
    protected function initialise(ServiceLocatorInterface $serviceLocator, $controller) { 
     $config = $serviceLocator->get('config'); 
     $controller->setConfig($config); 
    } 
} 

class ControllerFactory extends AbstractControllerFactory implements FactoryInterface 
{ 
    public function createService(ServiceLocatorInterface $serviceLocator) { 
     $controller = new \MyModule\Controller\MyController(); 
     $this->initialise($serviceLocator, $controller); 
     return $controller; 
    } 
} 
1

或更清潔:添加你的控制器作爲invokables到config,然後做這樣的事情果然你的控制器到一個俏皮話:

abstract class AbstractControllerFactory implements FactoryInterface 
{ 
    protected $controllerKey; 

    public function createService(ServiceLocatorInterface $serviceLocator) { 
     $config  = $serviceLocator->get('config'); 
     $controller = $serviceLocator->get($this->controllerKey); 
     $controller->setConfig($config); 
     return $controller; 
    } 
} 

class ControllerFactory extends AbstractControllerFactory implements FactoryInterface 
{ 
    protected $controllerKey = 'mymodule_controller_mycontroller'; 
}