2013-02-16 14 views
9

Ich bin wirklich verwirrt wann getServiceLocator verwenden und wann nicht. Als Beispiel:ZF2 wenn getServiceLocator() zu verwenden ist und wenn nicht

+ Module 
-+ Helloworld 
--+ src 
---+ Controller 
----+ IndexController.php 
----+ IndexControllerFactory.php 

---+ Service 
----+ LogginService.php 
----+ GreetingService.php 
----+ GreetingServiceFactory.php 

GreetingServiceFactory.php hat den Inhalt:

<?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', array(
      $loggingService, 
      'onGetGreeting' 
     )); 

     return $greetingService; 
    } 
} 

Und IndexControllerFactory.php hat den Inhalt:

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

Wie Sie sehen können, ich brauche $ Servicelocator -> getServiceLocator() in meiner ControllerFactory, aber nicht in meiner ServiceFactory. Warum? Beide verwenden dieselbe Schnittstelle ServiceLocatorInterface, die nicht einmal die Methode getServiceLocator() definiert.

module.config.php:

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

ich jede Klärung schätzen würde :)

einen schönen Tag!

Antwort

20

Die Methode getServiceLocator auf der AbstractPluginManager definiert ist, da es die ServiceLocatorAwareInterface implementiert. Wie Maks3w darauf hingewiesen hat, ist es nicht Teil der ServiceLocatorInterface, also vermeiden Sie es, wenn Sie eine Service Factory implementieren.

Sie können trotzdem Ihre Fabrik als Verschluss definieren und es immer noch verwenden:

class MyModule 
{ 
    public function getControllerConfig() 
    { 
     return array(
      'factories' => array(
       'IndexController' => function (
        \Zend\ServiceManager\AbstractPluginManager $pm 
       ) { 
        $ctr = new IndexController(); 

        $ctr->setGreetingService(
         $pm 
          ->getServiceLocator() 
          ->get('greetingService') 
        ); 

        return $ctr; 
       }, 
      ), 
     ); 
    } 
} 

Während in diesem Beispiel $pm in der Tat ist eine ServiceLocatorInterface Instanz, werden Sie noch einen Verweis auf die „main“ Service-Manager erhalten müssen Zugriff auf die 'greetingService'.

ZF2 verwendet verschiedene Service-Manager oder Plugin-Manager für Controller, Dienste, View-Helfer, Controller-Plugins, etc ... Das ist hauptsächlich für Typhinweis (schauen Sie sich die Schnittstelle des AbstractPluginManager an, um zu verstehen, wie Typstrenge erreicht wird) und für die Sicherheit.

In diesem Fall verhindert das Sicherheitsproblem den Zugriff auf Dienste, die keine Controller sind, insbesondere bei Routen mit einem dynamischen controller-Parameter. Deshalb werden Controller in einem separaten Plugin-Manager gespeichert.

Da der Controller-Plugin-Manager vom Service-Manager "main" erstellt wird, wird er auch initialisiert, dank der ServiceLocatorAwareInterface.

Um dies deutlich zu machen, ich habe eine grafische Darstellung der Beziehungen hinzugefügt (nicht die Fabrik schließen und nehmen Sie sie nicht als gültige UML):

Pseudo-UML

+1

Mit welchem ​​Werkzeug haben Sie dieses Diagramm erstellt? Sieht gut aus. – Leven

+1

@Leven das ist YUML – Ocramius

3

Denitively shouln't Sie getServiceLocator zu verwenden, da diese Methode nicht statt in ServiceLocatorInterface definiert ist get()

5

Wie Sie können Ich brauche $ serviceLocator-> getServiceLocator() in meiner ControllerFactory, aber nicht in meiner ServiceFactory. Warum?

Die Controller-Factory wird von einer anderen Service-Manager-Instanz (der "ControllerLoader") zur Haupt-Instanz aufgerufen. Dies ist so, dass der Dispatcher nicht dazu führen kann, dass eine willkürliche Klasse vom Hauptdienstmanager instanziiert wird.

Daher ist der $ serviceLocator des Controller-Werks nicht der, den Sie benötigen, wenn Sie 'greetingService' abrufen möchten, da 'greetingService' beim Haupt-Service-Manager registriert ist. Um den Haupt-Server-Manager vom Controller zu holen, verwenden Sie getServiceLocator() und Sie haben nun eine Instanz des Haupt-Service-Managers, von dem Sie erhalten können() 'Begrüßungsdienst'

Dies wird als 'Peering' bezeichnet. d. h. der Service-Manager "ControllerLoader" (der über den Schlüssel controllers in der Konfiguration oder getControllerConfiguration() in einer Modul-Klasse konfiguriert ist) wird mit dem Haupt-Service-Manager als Peer eingerichtet.

0

ich diese oben als Alternative anbiete, die die Basis module.config.php Setup

Jetzt tat ich so etwas ähnliches, aber mit etwas verwendet.

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(array(
      'entities_service'=>$this->entities_service, 
      'service_locator'=>$this->service_locator, 
     )); 
      return $this; 
     } 
     } 
    } 
... 
} 

Nun ist die Sache, die stapfte hatte ich zu der Erkenntnis zu kommen, hatte, dass ich nur den ersten Service-Locator benötigt verwenden, die während der Instanziierung jeden Controller verwendet wird, der diese Klasse erweitert ...

Bei Instanziierung: Diese Klasse wurde zuerst mit einem ControllerManager und dann mit dem ServiceManager für die Methode setServiceLocator versorgt.

Ich wollte nur den ControllerManger und seine Methode verwenden, damit der ServiceManager meine Fabriken instanziiert;

die teilweise auf meinem module.config.php

nun so etwas wie die für den richtigen Servicelocator folgenden verwendet habe, konnte ich filtern ... aber ich bin ein Fan von so wenig Kesselblech verwendet als erforderlich ...

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

    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName); 
} 
Verwandte Themen