2016-12-06 57 views
3

在我的控制器中,通過服務,我從DB獲得了部件名稱列表(例如圖表,日曆等)。每個小部件都實現WidgetInterface,並可能需要其他服務作爲其自己的依賴關係。每個用戶的小部件列表可能不同,所以我不知道我需要在控制器中使用哪些小部件/依賴項。一般來說,我通過DI使用工廠來放置依賴項,但在這種情況下,我不知道控制器初始化時的依賴關係。 我想避免直接在控制器中使用服務定位器。我怎樣才能解決這個問題?我應該得到控制器工廠中的小部件名稱列表嗎?並根據小部件列表獲取所有依賴關係,並將其放置到控制器?ZF2,我在開始時不知道的依賴關係

謝謝,湯姆

解決方案

我解決我的問題的方式,建議Kwido和Sven比伊斯,這意味着,我建立了自己的插件管理器。

優點:我不需要直接在控制器中使用服務定位器,並且我有清晰和可擴展的方式來獲取不同類型的小部件。

謝謝。

回答

1

爲您的小部件創建您自己的Manager,就像某種ServiceManager一樣。

class WidgetManager extends AbstractPluginManager 

看一看:Samsonik tutorial - pluginManager。因此,您可以通過這種方式注入WidgetManager,並僅從該管理器中檢索小部件作爲您的函數:validatePlugin,檢查提取的實例是否使用WidgetInterface。請記住,您仍然可以調用父ServiceManager。

或者保持簡單併爲您的控制器構建一個插件,將您的小部件名稱映射到服務。然後,該插件可以使用serviceLocator/Manager來檢索您的小部件,無論它們是由工廠還是由invokableFactories創建的。所以你不直接注入所有的小部件,而只是在請求時才抓取它們。真的東西簡單化:

protected $map = [ 
    // Widget name within the plugin => Name or class to call from the serviceManager 
    'Charts' => Widget\Charts::class, 
]; 

public function load($name) 
{ 
    if (array_key_exists($name, $this->map)) { 
     return $this->getServiceManager()->get($this->map[$name]); 
    } 

    return null; 
} 

噴射全部控件可能有損於你的表現,所以你可能會考慮別的東西,因爲當你的小部件的清單長得這麼會的時間來處理您的請求。

希望這有助於你,並推動你朝某個方向發展。

1

這確實是一個有趣的問題。你可以考慮使用插件的小部件,它可以在飛行中加載。

依賴注射是一種很好的做法,但有時動態內容不可能實現。

做到這一點的另一種方法是製作自己的widget-manager。這個經理然後可以加載你需要的特定小部件。小部件管理器可以注入到控制器中。

編輯: 正如你在上面看到的,來自@kwido的同樣的想法。

1

我會使用一個單獨的服務並將其注入控制器。

interface UserWidgetServiceInterface 
{ 
    public function __construct(array $widgets); 
    public function getWidget($name); 
} 

控制器工廠

class MyControllerFactory 
{ 
    public function __invoke(ControllerManager $controllerManager, $name, $requestedName) 
    { 
     $serviceLocator = $controllerManager->getServiceLocator(); 

     $userWidgetService = $serviceLocator->get('UserWidgetService'); 

     return new MyController($userWidgetService); 
    } 
} 

然後加載小窗口的邏輯將被移動到UserWidgetServiceFactory

public function UserWidgetServiceFactory 
{ 
    public function __invoke(ServiceManager $serviceLocator, $name, $requestedName) 
    { 
     $userId = 123; // Load from somewhere e.g session, auth service. 

     $widgetNames = $this->getWidgetNames($serviceLocator, $userId); 
     $widgets = $this->loadWidgets($serviceManager, $widgetNames); 

     return new UserWidgetService($widgets); 
    } 

    public function getWidgetNames(ServiceManager $sm, $userId) 
    { 
     return ['foo','bar']; 
    } 

    public function loadWidgets(serviceManager $sm, array $widgets) 
    { 
     $w = []; 
     foreach($widgets as $widgetName) { 
      $w[$widgetName] = $sm->get($widgetName); 
     } 
     return $w; 
    } 
} 

loadWidgets()的調用會急切地加載所有的小部件;如果你想優化這個,你可以註冊你的小部件爲LazyServices