2016-05-05 27 views
2

我使用基於ZF2的Apigility。一旦請求發送到控制器的操作,我需要選擇適當的適配器來請求 - 基於輸入參數。zend框架2:如何正確地將工廠注入控制器以獲得不同的映射器類?

通常情況下,控制器是由ControllerFactory實例化的,在這裏你可以提供所有的依賴關係,比如說我需要som類型的mapper類來注入。如果我知道的話,很容易,我將在控制器內使用哪一個。如果我需要讓控制器決定使用哪個映射器,這是有問題的。

假設用戶請求類似getStatus與參數'adapter1'和另一個用戶正在訪問相同的操作,但與參數'adapter2'

所以,我需要注入adapter1映射器或adapter2映射器,它具有類似的接口,但具有不同的構造器。

如何處理這種情況的正確方法是什麼?

在可能的解決方案是提供某種工廠方法,它將提供請求的適配器,但是 - 應該避免使用SM int模型類。

另一種方法是直接在控制器的動作中使用SM,但這不是最好的方法,因爲我不能在另一個動作/控制器上重複使用'switch-case'邏輯。

請問該如何處理?

+0

我想你能夠訪問你的工廠使用SM請求對象。因此,在注入對控制器的依賴之前,只需抓住它並獲取參數並檢查條件。如果兩個適配器都屬於通用接口,則需要定義映射器接口。 –

+0

不幸的是,情況並非如此。似乎,在Apigility中,只有在調用操作後才能使用過濾參數,而不是在構造函數中。我已經測試過這個作爲第一個選項:) – Ivan

回答

0

你可以使用控制器插件。

像這樣,您可以在需要時在控制器內部獲得適配器,而無需注入ServiceManager,也無需向工廠添加所有邏輯。只有在您的控制器操作方法中請求適配器時,該適配器纔會被實例化。

首先,你需要創建(延長Zend\Mvc\Controller\Plugin\AbstractPlugin)控制器插件類:

<?php 
namespace Application\Controller\Plugin; 

use Zend\Mvc\Controller\Plugin\AbstractPlugin; 

class AdapterPlugin extends AbstractPlugin{ 

    protected $adapterProviderService; 

    public function __constuct(AdapterProviderService $adapterProviderService){ 
     $this->adapterProviderService = $adapterProviderService; 
    } 

    public function getAdapter($param){ 
     // get the adapter using the param passed from controller 

    } 
} 

然後工廠在類中注入你的服務:

<?php 
namespace Application\Controller\Plugin\Factory; 

use Application\Controller\Plugin\AdapterPlugin; 

class AdapterPluginFactory implements FactoryInterface 
{ 
    /** 
    * @param ServiceLocatorInterface $serviceController 
    * @return AdapterPlugin 
    */ 
    public function createService(ServiceLocatorInterface $serviceController) 
    { 
     $serviceManager = $serviceController->getServiceLocator(); 
     $adapterProvicerService = $serviceManager>get('Application\Service\AdapterProviderService'); 
     return new AdapterPlugin($adapterProviderService); 
    } 
} 

然後,你需要註冊你的插件在你的module.config.php

<?php 
return array(
    //... 
    'controller_plugins' => array(
     'factories' => array(
      'AdapterPlugin' => 'Application\Controller\Plugin\Factory\AdapterPluginFactory', 
     ) 
    ), 
    // ... 
); 

現在你可以使用這裏面你的控制器動作是這樣的:

protected function controllerAction(){ 
    $plugin = $this->plugin('AdapterPlugin'); 
    // Get the param for getting the correct adapter 
    $param = $this->getParamForAdapter(); 
    // now you can get the adapter using the plugin 
    $plugin->getAdapter($param); 
} 

瞭解更多關於控制器插件here in the documentation

+0

非常感謝解釋,似乎這對我來說是最好的選擇。我會接受答案,只是請多一個問題:你認爲我可以直接在插件的getAdapter()方法中使用SM,而不是自定義的AdapterProvider? – Ivan

+0

@Ivan,當然,在工廠實例化時直接將適配器插入控制器插件會更好。 – Wilt

+0

這是正確的,但在場景中,有很多不同的適配器可用,只需要其中的少數適配器 - 可能會更好,但不要實例化所有這些適配器,但只是要求..這是一個理論上的問題,我只是試圖選擇最好的方法:)我試圖找到一些「懶加載」的工廠方法,如果你明白我的意思 – Ivan