ZF2 quando usare getServiceLocator () e quando no

Sono davvero confuso su quando utilizzare getServiceLocator e quando no. Come esempio:

+ Module -+ Helloworld --+ src ---+ Controller ----+ IndexController.php ----+ IndexControllerFactory.php ---+ Service ----+ LogginService.php ----+ GreetingService.php ----+ GreetingServiceFactory.php 

GreetingServiceFactory.php ha il contenuto:

 <?php namespace Helloworld\Service; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class GreetingServiceFactory implements FactoryInterface { public function createService (ServiceLocatorInterface $serviceLocator) { $greetingService = new GreetingService(); $greetingService->setEventManager($serviceLocator->get('eventManager')); $loggingService = $serviceLocator->get('loggingService'); $greetingService->getEventManager()->attach('getGreeting', arrays( $loggingService, 'onGetGreeting' )); return $greetingService; } } 

E IndexControllerFactory.php ha il contenuto:

 <?php namespace Helloworld\Controller; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; class IndexControllerFactory implements FactoryInterface { public function createService (ServiceLocatorInterface $serviceLocator) { $ctr = new IndexController(); $ctr->setGreetingService($serviceLocator->getServiceLocator() ->get('greetingService')); return $ctr; } } 

Come puoi vedere, ho bisogno di $ serviceLocator-> getServiceLocator () nel mio ControllerFactory ma non nel mio ServiceFactory. Perché? Entrambi utilizzano la stessa interface ServiceLocatorInterface che non definisce nemless il metodo getServiceLocator ().

module.config.php:

 'controllers' => arrays( 'factories' => arrays( 'Helloworld\Controller\Index' => 'Helloworld\Controller\IndexControllerFactory' ) ) , 'service_manager' => arrays( 'invokables' => arrays( 'loggingService' => 'Helloworld\Service\LoggingService' ), 'factories' => arrays( 'greetingService'=> 'Helloworld\Service\GreetingServiceFactory' ), ) 

Gradirei qualsiasi chiarimento 🙂

Buona giornata!

Il metodo getServiceLocator è definito su AbstractPluginManager , poiché implementa ServiceLocatorAwareInterface . Come sottolineato da Maks3w, non fa parte di ServiceLocatorInterface , quindi evita di utilizzarlo durante l'implementazione di un service factory.

Puoi comunque definire la tua fabbrica come chiusura e ancora usarla:

 class MyModule { public function getControllerConfig() { return arrays( 'factories' => arrays( 'IndexController' => function ( \Zend\ServiceManager\AbstractPluginManager $pm ) { $ctr = new IndexController(); $ctr->setGreetingService( $pm ->getServiceLocator() ->get('greetingService') ); return $ctr; }, ), ); } } 

Mentre in questo esempio $pm è in effetti un'istanza di ServiceLocatorInterface , sarà comunque necessario get un riferimento al gestore servizi "principale" per accedere a 'greetingService' .

ZF2 utilizza diversi gestori di servizi o gestori di plug-in per controller, servizi, helper di visualizzazione, plug-in del controller, ecc. Questo è principalmente per l'hint di tipo (guarda l'interface di AbstractPluginManager per capire come viene raggiunta la rigidità del tipo) e per la sicurezza.

In questo caso, il problema di sicurezza non consente l'accesso a servizi che non sono controllori, specialmente con routes con un parametro di controller dinamico. Ecco perché i controllori sono tenuti in un gestore di plugin separato.

Poiché il gestore del plug-in del controller viene creato dal gestore servizi "principale", viene anche inizializzato grazie a ServiceLocatorAwareInterface .

Per rendere questo più chiaro, ho aggiunto un grafico delle relazioni (non include la fabbrica e non la prendo come UML valido):

Pseudo-UML

Come puoi vedere, ho bisogno di $ serviceLocator-> getServiceLocator () nel mio ControllerFactory ma non nel mio ServiceFactory. Perché?

Il factory del controller viene chiamato da un'altra istanza del gestore servizi (il "ControllerLoader") a quella principale. Questo è così che il dispatcher non può determinare l'istanziazione di una class arbitraria da parte del responsabile del servizio principale.

Di conseguenza, $ serviceLocator del controllore factory non è quello necessario quando si desidera recuperare 'greetingService', poiché 'greetingService' è registrato con il gestore dei servizi principale. Per get il server manager principale dal controller uno, si usa getServiceLocator () e ora si ha un'istanza del gestore servizi principale da cui è ansible get () 'servizio di saluto'

Questo è noto come "peering". cioè il gestore di servizi "ControllerLoader" (quello configurato tramite la chiave 'controller' nella config o getControllerConfiguration () in una class Module) viene impostato con il gestore di servizi principale come peer.

In modo denitativo non usi getServiceLocator poiché quel metodo non è definito in ServiceLocatorInterface invece usa get()

Ti sto offrendo un'alternativa che usa la configuration di base module.config.php

Ora stavo facendo qualcosa di simile ma usando qualcosa di simile.

 class BaseServices extends AbstractActionController implements ServiceLocatorAwareInterface{ ... public function setServiceLocator(ServiceLocatorInterface $serviceLocator){ if($serviceLocator instanceof ControllerManager){ $this->service_locator = $serviceLocator->getServiceLocator(); $this->entities_service = $this->service_locator ->get('entities_service'); $this->session = new Session(arrays( 'entities_service'=>$this->entities_service, 'service_locator'=>$this->service_locator, )); return $this; } } } ... } 

Ora la cosa che mi aveva messo in difficoltà era di wherer realizzare che avevo bisogno di usare solo il primo localizzatore di servizio che viene usato durante l'istanziazione di qualsiasi controller che estende questa class …

In istanziazione: questa class è stata prima nutrita con un ControllerManager e successivamente con ServiceManager per il metodo setServiceLocator.

Volevo solo usare ControllerManger e il suo metodo per far sì che ServiceManager istanziasse le mie fabbriche;

il parziale sul mio module.config.php

 module.config.php { ... 'service_manager' => 'abstract_factories' => arrays( 'Zend\Log\LoggerAbstractServiceFactory', ), 'factories' => arrays( 'entities_service' => 'Service\Providers\Entities', ), 'invokables' => arrays( 'post' => 'Service\Controllers\Runtime\Post', ), ), } 

Ora avrei potuto usare qualcosa di simile al seguente per filtrare il ServiceLocator giusto … eppure sono un fan dell'uso di un piccolo piatto di caldaia quanto necessario …

 interface AbstractFactoryInterface { public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); }