2012-10-21 16 views
5

La mia domanda in breve: Posso utilizzare una singola fabbrica per più controller?Fabbrica singola per più controller?

Maggiori dettagli:

Ho alcune impostazioni specifiche non modulo globale in /config/autoload/global.php che assomigliano a questo:

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

    // More ZF default configuration ... 
); 

Ora voglio fare queste impostazioni accessibile in ogni controller senza dover chiamare il $this->getServiceLocator()->get('config') tutto il tempo.

Quindi la mia idea era di introdurre un attributo di classe $settings nel mio AbstractController che viene iniettato con l'array di configurazione. Ho provato a recuperare la configurazione direttamente nel costruttore di AbstractController. Tuttavia, getServiceLocator() non sembra pronto al momento e restituisce NULL.

ho potuto costruire fabbriche controller per ogni controller e iniettare le impostazioni di questo tipo:

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

ma sarebbe lo stesso più e più volte. Quindi la mia domanda è: Posso usare una singola fabbrica per più controller?

Nel mio module.config.php ho potuto specificare una singola classe fabbrica per più controller:

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

Ma in fabbrica ho bisogno di restituire l'oggetto controller attuale a mano (vedi esempio sopra) che ovviamente funziona solo con una fabbrica per controller.

Spero, ho chiarito il mio problema.

UPDATE 2013/03/24:

Anche se ho seguito la soluzione suggerita attraverso la creazione di un inizializzatore, non ho mai veramente piaciuto usarlo solo per l'iniezione della configurazione.

Quindi ho continuato a scavare e ho finito per creare un plug-in Controller per ricevere le impostazioni.

Il codice per il plugin si presenta così:

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

Dopo aver aggiunto il plugin nella module.config.php con

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

posso accedere con facilità le impostazioni all'interno di un controllore semplicemente chiamando $this->settings(). Spero che questo aiuti chiunque.

risposta

6

Si potrebbe provare ad allegare un inizializzatore, quindi mentre il controller viene creato, l'istanza viene confrontata con gli inizializzatori noti. Se l'istanza corrisponde a una determinata interfaccia o classe astratta, è possibile applicare una logica comune.

Non ho testato questo approccio con i controller ma dato che ControllerLoader è un tipo di ServiceManager/ServiceLocator dovrebbe funzionare in teoria.

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

Poi l'Initalizer sarebbe simile:

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

     // Do something for this instance 
    } 
} 
+0

Grazie per la vostra idea. Lo stesso inizializzatore funziona come descritto, tuttavia una volta aggiunto all'array 'controller', i mapping del controller si perdono in qualche modo e viene visualizzato un errore che dice * "Il controller richiesto non può essere mappato su una classe controller esistente." * sembra che sia i "invokable" che gli "inizializzatori" all'interno dei "controllers" si mordano a vicenda. Hai qualche suggerimento? – Rob

+0

Vorrei tornare indietro ai soli invokable, quindi applicare l'inizializzatore, quindi eseguire il debug se l'inizializzatore riceve un'istanza. Il messaggio di errore generato potrebbe essere per una serie di motivi, assicurarsi che tutte le definizioni di utilizzo siano corrette e che non vi siano errori. Per scavare più a fondo vorrei dare un'occhiata a \ Zend \ Mvc \ Service \ ControllerLoaderFactory.php e seguirlo fino a \ Zend \ Mvc \ Controller \ ControllerManager.php - spero che aiuti. – DrBeza

+0

Trovato la causa: è la chiamata '$ serviceLocator-> get ('Config')' in Initializer :: initialize() che genera un'eccezione * servizio non trovata *. Quindi sembra che la configurazione non sia pronta alla fase di inizializzazione. E ancora non riesco a ottenere le mie impostazioni nel controller :-(Proverò ora una soluzione. – Rob

1

Non so come hai fatto un aggiornamento futuro "UPDATE 2013/03/24";)

Perché non basta usa controller come hai suggerito ma inserisci il codice che desideri in tutti i controller in una fabbrica astratta da cui poi erediti, ad esempio:

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

o anche più pulito: aggiungi i controller come invokables alla configurazione, poi fare qualcosa di simile, che trasforma i controller in one-liner:

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'; 
} 
Problemi correlati