2012-10-21 15 views
5

Moje pytanie w skrócie: czy mogę używać jednej fabryki dla wielu kontrolerów?Jedna fabryka dla wielu kontrolerów?

Więcej szczegółów:

Mam kilka ustawienia globalne specyficzne non-moduł w /config/autoload/global.php które wyglądają tak:

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

    // More ZF default configuration ... 
); 

Teraz chcę, aby te ustawienia dostępne w każdym kontrolerze bez konieczności ciągłego dzwonienia pod numer $this->getServiceLocator()->get('config').

Więc moim pomysłem było wprowadzenie atrybutu klasy $settings w moim AbstractController, który zostanie wprowadzony z tablicą konfiguracji. Próbowałem pobrać konfigurację bezpośrednio w konstruktorze AbstractController. Jednak getServiceLocator() nie wydaje się gotowy w tym czasie i zwraca NULL.

mogłem budować fabryki kontroler dla każdego kontrolera i wstrzyknąć ustawienia jak poniżej:

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

Ale byłoby to samo w kółko. Moje pytanie brzmi: czy mogę używać jednej fabryki dla wielu kontrolerów?

W moim module.config.php mogę określić pojedynczy klasy fabrycznej dla wielu kontrolerów:

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

Ale w fabryce muszę wrócić rzeczywisty obiekt Controller ręcznie (patrz przykład powyżej) który oczywiście działa tylko z jedną Fabryką na Sterownika.

Mam nadzieję, że mój problem jest jasny.

UPDATE 24.03.2013:

Chociaż raz pierwszy zastosowaną sugerowane rozwiązanie tworząc inicjator, tak naprawdę nigdy nie lubiłem go używać tylko do wstrzykiwania konfiguracji.

Więc ciągle kopałem i skończyłem tworzyć wtyczkę kontrolera, aby otrzymać ustawienia.

Kod dla wtyczki wygląda następująco:

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; 
    } 
} 

Po dodaniu wtyczki w module.config.php z

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

można łatwo uzyskać dostęp do moich ustawień w sterowniku przez po prostu dzwonię pod numer $this->settings(). Mam nadzieję, że to pomoże każdemu.

Odpowiedz

6

Możesz spróbować podłączyć inicjalizator, a następnie, gdy zostanie utworzony kontroler, instancja jest sprawdzana względem znanych inicjalizatorów. Jeśli instancja pasuje do danego interfejsu lub klasy abstrakcyjnej, można zastosować pewną wspólną logikę.

Nie testowałem tego podejścia z kontrolerami, ale biorąc pod uwagę, że ControllerLoader jest typem ServiceManager/ServiceLocator powinien on teoretycznie działać.

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

Następnie Initalizer będzie wyglądać następująco:

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

     // Do something for this instance 
    } 
} 
+0

Dziękujemy za pomysł. Sam inicjalizator działa tak, jak opisałeś, jednak gdy dodam go do tablicy "kontrolerów", mapowania kontrolera jakoś się zgubią i pojawia się błąd mówiący: "Żądanego kontrolera nie można zmapować do istniejącej klasy kontrolera." * To wydaje się, że oba "invokable" i "initializers" w ramach "kontrolerów" gryzą się nawzajem. Masz jakieś sugestie? – Rob

+0

Chciałbym przewinąć z powrotem do just invokables, a następnie zastosować inicjalizator - a następnie debugować, jeśli inicjator pobiera instancję. Komunikat o błędzie może być z wielu powodów, upewnij się, że wszystkie definicje użytkowania są poprawne i nie ma błędów. Aby zagłębić się głębiej, zajrzałbym do \ Zend \ Mvc \ Service \ ControllerLoaderFactory.php i podążałem za nim do \ Zend \ Mvc \ Controller \ ControllerManager.php - mam nadzieję, że to pomaga. – DrBeza

+0

Znaleziono przyczynę: Jest to wywołanie '$ serviceLocator-> get ('Config')' w Initializer :: initialize(), które zgłasza wyjątek * service not found *. Wygląda na to, że konfiguracja nie jest gotowa w fazie inicjalizacji. Nadal nie mogę wprowadzić swoich ustawień do kontrolera :-(Spróbuję obejść teraz: – Rob

1

Nie wiem, jak to zrobiłeś przyszłej aktualizacji "Aktualizacja 2013-03-24";)

Dlaczego nie można po prostu użyj kontrolerów takich jak Ty, ale umieść kod, który chcesz we wszystkich kontrolerach, w abstrakcyjnej fabryce, z której następnie dziedziczysz, na przykład:

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

lub nawet czystsze: dodać kontrolerów jako invokables do config, a następnie zrobić coś takiego, która zamienia kontrolery do jednej wkładki:

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'; 
} 
Powiązane problemy