turk porno porno escort rokettube
Ergebnis 1 bis 18 von 18

Thema: Kapitel 8.6 FactoryInterface

  1. #1
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard Kapitel 8.6 FactoryInterface

    Hallo,

    bzgl. der Auflösung von Abhängigkeiten mit Hilfe des FactoryInterface 3 Fragen.

    1. Auf Seite 186 wird von der vollständigen Auflösung von Abhängigkeiten gesprochen. Im Beispiel-Code auf GitHub "Kapitel 8" wurde diese aber nicht umgesetzt, oder? Es wird davon gesprochen, dass Interface Pizza\Service\ServiceInterface zu implmentieren. Welches Interface Pizza\Service\ServiceInterface?

    2. Nach vollständiger Umsetzung wird bei mir folgende Fehlermeldung ausgegeben: Controller of type Album\Controller\AlbumControllerFactory is invalid; must implement Zend\Stdlib\DispatchableInterface. Wo liegt der Fehler?

    AlbumControllerFactory:
    PHP-Code:
    namespace Album\Controller;

    use 
    Zend\ServiceManager\FactoryInterface;
    use 
    Zend\ServiceManager\ServiceLocatorInterface;

    class 
    AlbumControllerFactory implements FactoryInterface
    {
        public function 
    createService(ServiceLocatorInterface $serviceLocator)
        {
            
    $service $serviceLocator->getServiceLocator()->get('Album\Service\AlbumTableService');

            
    $controller = new IndexController($service);
            return 
    $controller;
        }

    AlbumController:
    PHP-Code:
    namespace Album\Controller;

    use 
    Album\Service\AlbumTableService;
    use 
    Zend\Mvc\Controller\AbstractActionController;
    use 
    Zend\View\Model\ViewModel;

    class 
    AlbumController extends AbstractActionController
    {
        protected 
    $albumTableService;

        public function 
    __construct(AlbumTableService $service)
        {
            
    $this->setAlbumTableService($service);
        }

        public function 
    setAlbumTableService(AlbumTableService $service)
        {
            
    $this->albumTableService $service;
        }

        public function 
    getAlbumTableService()
        {
            return 
    $this->albumTableService;
        }

        ...

    AlbumTableService:
    PHP-Code:
    namespace Album\Service;

    use 
    Album\Model\Album;
    use 
    Album\Model\AlbumTable;
    use 
    Zend\Db\ResultSet\ResultSet;
    use 
    Zend\Db\TableGateway\TableGateway;
     
    class 
    AlbumTableService
    {
        public function 
    __construct()
        {
            
    $sm $this->getApplication()->getServiceManager();
            
    $dbAdapter $sm->get('Zend\Db\Adapter\Adapter');
            
    $resultSetPrototype = new ResultSet();
            
    $resultSetPrototype->setArrayObjectPrototype(new Album());
            
    $tableGateway = new TableGateway('album'$dbAdapterNULL$resultSetPrototype);
            return new 
    AlbumTable($tableGateway);
        }

    Module.php:
    PHP-Code:
    namespace Album;

    ...

    class 
    Module
    {
        ...

        public function 
    getServiceConfig()
        {
            return array(
                
    'invokables' => array(
                    
    'Album\Service\AlbumTableService' => 'Album\Service\AlbumTableService',
                ),
                ...
            );
        }

        ...

    3. Im Prinzip sind die drei Methoden "__construct()", "setPizzaService()" und "getPizzaService()" redundant, da diese sowohl 1:1 im IndexController als auch im RestController definiert sind. Ich habe früher einmal gelernt, in der OOP sollte man so etwas vermeiden? Schlägt hier der Nutzen aus der vollkommenden Auflösung von Abhängigkeiten, die Lehre der OOP?

    Viele Grüße

    Alex

  2. #2
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    zu 1.)

    Ja, das Interface ist nicht Teil der Dateien für Kapitel 8. Der ganze Absatz beschreibt nur ein gewisses Problem und den möglichen Lösungsweg. Das Interface muss somit selber implementiert werden. Wenn du statt der konkreten Klasse PizzaService nun in den Methodensignaturen PizzaServiceInterface verwendest, könntest du auch einen anderen PizzaService verwenden, solange dieser nur das PizzaServiceInterface implementiert hat. Ich habe mich gegen eine Implementation dieser Vorgehensweise entschieden, um den Rahmen nicht noch weiter zu sprengen. Wenn du dir später im Buch z.B. das Pizza Modul anschaust, siehst du die Implementation mithilfe von Interfaces.

    zu 2.)

    Könntest du noch sagen, wo genau dieser Fehler auftritt? Welche Datei und welche Zeile, also den Trace? Außerdem vermute ich ein Problem in der Konfiguration der Controller. Könntest du den Teil aus der model.config.php oder Module.php auch mal reinkopieren, wo deine Controller konfiguriert werden?

    zu 3.)

    Theoretisch könntest du hier zwei Lösungswege gehen.

    a) Du könntest für das Modul einen abstrakten Controller schreiben, der diese Methoden implementiert, und alle Controller aus diesem Modul erweitern dann diesen abstrakten Controller.

    b) Du könntest dir ein Controller Plugin erstellen, dessen einziger Zweck darin besteht, den PizzaService zugreifbar zu machen. Damit schleicht sich aber durch die Hintertür natürlich wieder eine Abhängigkeit zu deinem Controller Plugin ein. Deshalb würde ich Variante a) bevorzugen.

    Gruß,

    Ralf

  3. #3
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    bzgl. Frage 2, anbei der gewünschte Code.

    module.config.php:
    PHP-Code:
    return array(
        
    'controllers' => array(
            
    'invokables' => array(
                
    'Album\Controller\Album' => 'Album\Controller\AlbumControllerFactory',
            ),
        ),
        ...
    ); 
    Erhalte den folgenden Fehler:
    Code:
    Es trat ein 404 Fehler auf
    
    Page not found.
    
    Der angeforderte Controller ist nicht aufrufbar.
    Controller:Album\Controller\Album(wird aufgelöst in invalid controller class or alias: Album\Controller\Album)
    
    
    Zusätzliche Information: Zend\Mvc\Exception\InvalidControllerException Datei: /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/ControllerManager.php:104 Meldung: Controller of type Album\Controller\AlbumControllerFactory is invalid; must implement Zend\Stdlib\DispatchableInterface Stapelüberwachung: #0 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php(105): Zend\Mvc\Controller\ControllerManager->validatePlugin(Object(Album\Controller\AlbumControllerFactory)) #1 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/ControllerManager.php(120): Zend\ServiceManager\AbstractPluginManager->get('Album\Controller...', Array, false) #2 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/Mvc/DispatchListener.php(97): Zend\Mvc\Controller\ControllerManager->get('Album\Controller...') #3 [internal function]: Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent)) #4 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(460): call_user_func(Array, Object(Zend\Mvc\MvcEvent)) #5 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php(204): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure)) #6 /kunden/367586_78073/demo/vendor/zendframework/zendframework/library/Zend/Mvc/Application.php(294): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure)) #7 /kunden/367586_78073/demo/public/index.php(12): Zend\Mvc\Application->run() #8 {main}
    Viele Grüße

    Alex
    Geändert von Alex.Mod (03.05.2013 um 19:59 Uhr)

  4. #4
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Ganz kurz: Du verwendest "invokables" mit einer Factory. Das kann nicht klappen. Ändere das in "factories" und es sollte laufen.

    Gruß,

    Ralf

  5. #5
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    sorry, very painful.

    Wie der Name schon sagt... "Factories" bei "Factory" und "Invokables" bei "normalen" Controllern, stimmts?

    Viele Grüße

    Alex

  6. #6
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    habe es nun theoretisch verstanden und praktisch würde es auch funktionieren, aber in meinem Anwendungsfall hilft mir der Service eigentlich gar nicht weiter?

    Wollte eigentlich die Erzeugung der Instanz eines TableGateway (AlbumTable) vom ServiceManager in einen Service verlagern. Bin mir nicht mehr so sicher, ob das so sinnvoll ist. Denn der Service würde dann eine Instanz von TableGateway (AlbumTable) und nicht eine Instanz des Service selbst, bspw. PizzeService, zurückgeben.

    Was denkst du bzw. ist deine Empfehlung?

    Viele Grüße

    Alex

  7. #7
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    theoretisch fällt mir folgende Implementierungsmöglichkeit ein, um das Problem (siehe oben) lösen zu können.

    PHP-Code:
    protected $dbAdapter;
    protected 
    $tableGateway;

    public function 
    setDbAdpater($dbAdpater)
    {
        
    $this->dbAdapter $dbAdpater;
    }

    protected function 
    getTableGateway()
    {
        if (!
    $this->tableGateway)
        {
            
    $resultSetPrototype = new ResultSet();
            
    $resultSetPrototype->setArrayObjectPrototype(new Album());
            
    $tableGateway = new TableGateway('album'$this->dbAdapterNULL$resultSetPrototype);
            
    $this->tableGateway = new AlbumTable($tableGateway);
        }
        return 
    $this->tableGateway;
    }

    public function 
    __call($name$arguments)
    {
        return 
    call_user_func_array(array($this->getTableGateway(), $name), $arguments);

    Was denkst du bzw. hast du eine andere Empfehlung, welche evtl. sauber wäre?

    Viele Grüße

    Alex
    Geändert von Alex.Mod (02.05.2013 um 23:32 Uhr)

  8. #8
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    ehrlich gesagt, habe ich noch nicht genau verstanden, was du machen möchtest. Wahrscheinlich bin ich noch nicht ganz wach. Der Code aus dem Beispiel oben soll wo genau stehen?

    Gruß,

    Ralf

  9. #9
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    wollte eigentlich über den Service via TableGateway auf die entsprechende Datenbank-Tabelle zugreifen.

    In deinem Beispiel sind die Methoden, bspw. "fetchAll()", im Service implementiert, bei mir sind diese im TableGateway (AlbumTable) implementiert. D.h müsste hier über den Service auf dieses TableGateway zugreifen. Die Frage ist hier, ob die Umsetzung mittels eines Service hier überhaupt so sinnvoll ist? Und wie die bestmöglich Code aussieht, um über den Service auf das TableGateway zugreifen zu können?

    Ich dachte hier theoretisch an eine Methode "__call()", die den Aufruf, bspw. "fetchAll()", einfach weitergibt. D.h. der Code, entspricht dem Code des Service.

    Viele Grüße

    Alex

  10. #10
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    also der Service ist vom Prinzip her das Bindeglied zwischen dem Model und dem Controller. Deshalb nenne ich es häufig auch den Model-Service. Er holt die Daten aus der Datenbank mithilfe des TableGateway und gibt sie an den Controller als Entitätsinstanzen. Er bekommt vom Controller neue Daten (sei es aus einem Formular oder einem Webservice) und übergibt sie an das TableGateway zum Schreiben. Oft habe ich im Service eine Methode fetchAll(), die nur an die gleichnamige Methode es TableGateway durchreicht. Ich könnte selbiges Ziel auch mit solchen Aufrufen erreichen:

    PHP-Code:
    $this->getService()->getTable()->fetchAll() 
    statt

    PHP-Code:
    $this->getService()->fetchAll() 
    Nun könnte es aber durchaus mal vorkommen, dass ich kein TableGateway als Datenquelle verwende, sondern die Daten vielleicht von einem Webservice abgreife. Dann könnte es durchaus sein, dass ich den fetchAll() Aufruf nicht einfach durchreichen kann, sondern entsprechend anpassen muss. Der Controller braucht aber nicht zu wissen, dass die Daten per TableGateway oder Webservice oder Datei bereit gestellt werden. Deshalb ist dies hier meist einfacher nachzuvollziehen:

    PHP-Code:
    $this->getService()->fetchAll() 
    Natürlich könntest du dir jetzt eine __call() Methode im Model-Service schreiben, die alle Aufrufe für nicht vorhandene Methoden erst einmal ans TableGateway weiterleitet. Damit sparst du dir vielleicht eine Menge Durchreichemethoden. Du verlierst aber wahrscheinlich in deiner IDE eine vernünftige Codevervollständigung, da dir alle über __call() abgefangenen Methoden nicht mehr vorgeschlagen werden können.

    Ich hoffe, ich konnte dir damit weiter helfen.

    Gruß,

    Ralf

  11. #11
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    ok, dann ist meine Implementierung exakt so, wie du es beschrieben hast, nur eben via Methode "__call()".

    Dein Argument bzgl. Codevervollständigung ist ein guter Hinweis, aber spare mir eben so sowohl im TableGateway als auch im Service alle Methoden "redundant" zu implementieren.

    Werde aber dennoch den Weg der "doppelten" Implementierung umsetzen, da die Applikation sonst evtl. auch etwas umständlich zu lesen ist.

    Zurück zum FactoryInterface: Wäre es eigentlich denkbar, ein AbstractFactoryController zu implementieren? Habe zwei FactoryController, dessen Code in der Methode "createService(ServiceLocatorInterface $serviceLocator)" eigentlich nahezu identisch sind. D.h. hätte dann AbstractAlbumFactoryController, AlbumFactoryController und AlbumController. Oder wäre dies zuviel Verschachtelung, nur um Redundanzen zu vermeiden?

    Viele Grüße

    Alex
    Geändert von Alex.Mod (09.05.2013 um 17:53 Uhr)

  12. #12
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo,

    es spricht nichts dagegen, auch die abstrakten Fabriken für die Initialisierung von Controllern zu verwenden. Genau für solche Fälle sind diese ja gedacht. :-)

    Gruß,

    Ralf

  13. #13
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    stehe jetzt vor mehreren Fragen bzgl. der ControllerFactory, dem Service und Listener.

    ControllerFactory:
    PHP-Code:
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        
    $dbAdapter $serviceLocator->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
        
    $service $serviceLocator->getServiceLocator()->get('Album\Service\AlbumTableService');
        
    $service->setDbAdpater($dbAdapter);
        
    $logger $serviceLocator->getServiceLocator()->get('AlbumLogger');
        
    $service->setLogger($logger);
        
    $controller = new AlbumController($service);
        return 
    $controller;

    Service:
    PHP-Code:
    protected $dbAdapter;
    protected 
    $tableGateway;
    protected 
    $logger;

    public function 
    setDbAdpater($dbAdpater)
    {
        
    $this->dbAdapter $dbAdpater;
    }

    public function 
    setLogger($logger)
    {
        
    $this->logger $logger;
    }

    public function 
    getTableGateway()
    {
        if (!
    $this->tableGateway)
        {
            
    $eventFeature = new EventFeature();
            
    $eventFeature->getEventManager()->attach(new AlbumLoggerPostListener($this->logger));
            
    $resultSetPrototype = new ResultSet();
            
    $resultSetPrototype->setArrayObjectPrototype(new Album());
            
    $tableGateway = new TableGateway('album'$this->dbAdapter$eventFeature$resultSetPrototype);
            
    $this->tableGateway = new AlbumTable($tableGateway);
        }
        return 
    $this->tableGateway;

    Listener:
    PHP-Code:
    protected $logger NULL;
    protected 
    $listeners = array();

    public function 
    __construct($logger)
    {
        
    $this->logger $logger;
    }

    public function 
    attach(EventManagerInterface $events)
    {
        
    $this->listeners[] = $events->attach('postInsert', array($this'logPostInsertDebug'));
    }

    public function 
    detach(EventManagerInterface $events)
    {
        foreach (
    $this->listeners as $index => $listener)
        {
            if (
    $events->detach($listener))
            {
                unset(
    $this->listeners[$index]);
            }
        }
    }

    public function 
    logPostInsertDebug(TableGatewayEvent $e)
    {
        
    $params $e->getParam('statement')->getParameterContainer();
        
    $data $params->getNamedArray();
        
    $id $e->getTarget()->getAdapter()->getDriver()->getLastGeneratedValue();
        
    $this->logger->log(\Zend\Log\Logger::DEBUG'INSERT ' $id ': ' serialize($data));

    Kurz gesagt, es funktioniert zwar, ist aber gefühlt irgendwie unglücklich gelöst.

    1.) Meine Instanz von Zend\Log\Logger ist in der Module.php als Shared in der Methode "getServiceConfig()" definiert. Da diese Instanz im Service benötigt wird, muss das ControllerFactory diese entsprechend im Service setzen "setLogger()" und der Service diese via Übergabeparameter der Methode "__construct()" dem Listener übergeben.
    Gibt es hier eine einfachere Möglichkeit oder eine Möglichkeit im Service oder der Methode "__construct()" im Listener auf den ServiceManager zugreifen zu können? Oder wäre es zulässig und dennoch guter Stil, dem Konstruktor einfach eine Instanz von Zend\Log\Logger stattdessen zu übergeben?

    2.) Nutze eine Instanz von Zend\Log\Logger für drei unterschiedliche Zwecke und somit in mindestens zwei Listener. Ist dies zulässig oder sollte hier aus Gründen der Übersichtlichkeit drei Instanzen von Zend\Log\Logger anstelle einer Instanz erzeugt werden?

    Module.php:
    PHP-Code:
    $logger = new Log\Logger();

    // LOG 1 -> Via STREAM
    $writer1 = new Writer\Stream($_SERVER['DOCUMENT_ROOT'] . '/data/log/album.log');
    $formatter1 = new Formatter\Simple('%timestamp% > %priorityName% (%priority%): ' '%message%');
    $writer1->setFormatter($formatter1);
    $logger->addWriter($writer1);
    $filter1 = new Filter\Priority(Log\Logger::INFO'='); // Only INFO
    $writer1->addFilter($filter1);

    // LOG 2 -> Via EMAIL
    $writer2 = new Writer\Mail($mail);
    $formatter2 = new Formatter\Simple('%timestamp% > %priorityName% (%priority%): ' '%message%');
    $writer2->setFormatter($formatter2);
    $logger->addWriter($writer2);
    $filter2 = new Filter\Priority(Log\Logger::CRIT); // From CRIT up to EMERG
    $writer2->addFilter($filter2);

    // LOG 3 -> Via DB
    $writer3  = new Writer\Db($sm->get('Zend\Db\Adapter\Adapter'), 'album_logger',  array('timestamp' => 'timestamp''priority' => 'priority',  'message' => 'message'));
    $logger->addWriter($writer3);
    $filter3 = new Filter\Priority(Log\Logger::DEBUG'='); // Only DEBUG
    $writer3->addFilter($filter3); 
    3.) Müssen eigene Events, die via "$this->getEventManager()->trigger()" im Controller ausgelöst werden immer als eigener Service implementiert werden (siehe Code-Listing Seite 109) oder kann ein solcher Event in einem Listener implementiert werden? Es geht mir darum, dass Code-Listing Seite 176 um einen eigenen Event "Foo", welcher via "$this->getEventManager()->trigger()" ausgelöst werden kann, zu erweitern. Und benötigt man für eigene Events, welche in allen Controller ausgelöst werden können sollten, immer den SharedManager?

    4.) Manchmal wird in der Methode "onBootstrap()" mit dem Übergabeparameter "MvcEvent" und manchmal mit dem Übergabeparameter "EventInterface" gearbeitet. Wann sollte welche Übergabeparameter genutzt werden? Und wann wird "$e->getApplication()" und wann "$e->getTarget()" genutzt?

    Viele Grüße

    Alex
    Geändert von Alex.Mod (09.05.2013 um 18:59 Uhr)

  14. #14
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    das muss ich nun erst einmal gedanklich auseinander nehmen.

    zu 1:

    Du solltest für deinen Service auch eine Factory erstellen. Darin können sowohl der Logger als auch die TableGateway Instanz gesetzt werden. Dann kannst du auch einiges aus dem Code von der Factory für den Controller vereinfachen. Die Factory für den Controller muss sich dann nur um die Injizierung des Services kümmern, während sich die Factory für den Service um die Injizierung des TableGateway und des Logger kümmert. Dadurch wird beides sauberer. Die getTableGateway() Methode in deinem Service kann dann auch bis auf das return entschlackt werden.

    zu 2:

    Es spricht nichts dagegen, eine Logger-Instanz für alle drei Logging-Arten zu verwenden. Genau dafür wurde Zend\Log unter anderem auch konzipiert. Und dass Zend\Log aus mehreren Listenern angestossen wird, ist auch kein Pronlem. Nur wenn du Fehler A nur durch Logger Writer X und Y und Fehler B nur durch Logger Z verarbeiten lassen möchtest, wären zwei Logger-Instanzen sinnvoll.

    zu 3:

    Da bin ich noch nicht ganz sicher, was du erreichen möchtest. Wichtig ist aber, dass es eben mehrere Event-Manager Instanzen gibt. So verwendet das MVC einen eigenen Event-Manager, der im besagten Beispiel auf Seite 176 verwendet wird und der die Events "route", "dispatch", "bootstrap", "finish", "dispatch.error", "render.error" und "render" sowie den Identifier "Zend\Mvc\Application" registriert hat. Die Event-Manager Instanz, die in den Controllern bereit steht, hat erst einmal keine Events und keine Identifier registriert. Möchtest du aus einem Controller heraus Events anstossen hast du nun zwei Wege:

    a) Wenn es sich um MVC Events handelt, kannst du diesen so erreichen:

    PHP-Code:
    $eventManager $this->getServiceLocator()->get('application')->getEventManager(); 
    Dann stehen dir die oben genannten Events und der Identifier zur Verfügung. Die Events kannst du über die Zend\Mvc\MvcEvent Konstanten notieren.

    b) Wenn es sich um Events in deinem Controller handelt, kannst du den Event-Manager so erreichen:

    PHP-Code:
    $eventManager  $this->getEventManager(); 
    Deine Events müsstest du aber im Vorfeld registrieren. Dies kannst du in der Controller Factory machen.

    PHP-Code:
    namespace Blog\Controller;

    use 
    Zend\ServiceManager\FactoryInterface;
    use 
    Zend\ServiceManager\ServiceLocatorInterface;

    class 
    BlogControllerFactory implements FactoryInterface
    {
        public function 
    createService(ServiceLocatorInterface $serviceLocator)
        {
            
    $sm         $serviceLocator->getServiceLocator();
            
    $service    $sm->get('Blog\Service\Blog');
            
    $controller = new BlogController();
            
    $controller->setBlogService($service);
            
            
    $eventManager $controller->getEventManager();
            
    $eventManager->attach('logger', function($e) { echo 'BlogController:logger Event'; }, 200);
            
            return 
    $controller;
        }

    Auslösen kannst du das Event dann in einer Aktionsmethode des Controllers wie folgt:

    PHP-Code:
    namespace Blog\Controller;

    use 
    Zend\Mvc\Controller\AbstractActionController;

    class 
    BlogController extends AbstractActionController
    {
        public function 
    indexAction()
        {
            
    $eventManager  $this->getEventManager();
            
    $eventManager->trigger('logger');
        }

    Da jeder Controller seine eigene Controller-Instanz hat, musst du Ereignisse, die für alle Controller gelten, im SharedEventManager registrieren.

    zu 4:

    Also die onBootstrap() Methode in der Module.php erwartet ein Objekt, das das EventInterface implementiert. Wenn deine Module.php das Zend\ModuleManager\Feature\BootstrapListenerInterf ace implementiert wird EventInterface verlangt. Übergeben wird aber ein Objekt MvcEvent, das EventInterface implementiert.

    Für das MvcEvent sind die Aufrufe getTarget() und getApplication() identisch, da das Target im MvcEvent eben das Application Objekt aus dem MVC ist. Zusatz: Bei dem ViewEvent z.B. gibt es kein getApplication() sondern nur getTarget() und das wiederum ist die Zend\View Instanz.

    Gruß,

    Ralf

  15. #15
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    habe Pkt. 1 nun - gekürzt - wie folgt umgesetzt.

    ControllerFactory:
    PHP-Code:
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        
    $service $serviceLocator->getServiceLocator()->get('Album\Service\AlbumTableService');
        return new 
    AlbumController($service);

    ServiceFactory:
    PHP-Code:
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        
    $dbAdapter $serviceLocator->getServiceLocator()->get('Zend\Db\Adapter\Adapter'); # LINE 12
        
    return new AlbumTableService($dbAdapter);

    Erhalte nun den Fehler: "Fatal error: Call to undefined method Zend\ServiceManager\ServiceManager::getServiceLoca tor() in AlbumTableServiceFactory.php on line 12".

    Ich habe daraufhin "$serviceLocator->getServiceLocator()->get('Zend\Db\Adapter\Adapter');" durch "$serviceLocator->get('Zend\Db\Adapter\Adapter');" ersetzt und es funktioniert.
    Warum funktioniert es im ControllerFactory nur mit "getServiceLocator()" und im ServiceFactory nur ohne "getServiceLocator()"?

    Viele Grüße

    Alex
    Geändert von Alex.Mod (10.05.2013 um 15:39 Uhr)

  16. #16
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    wie beim EventManager gibt es mehrere Instanzen vom ServiceManager. Der "globale" ServiceManager enthält z.B. alle Services, die das MVC benötigt sowie eigene Services, die über den Konfigurationsschlüssel "service_manager" in deinen Modulen definiert sind. Für Controller gibt es einen speziellen ServiceManager, der nur die Controller bereit hält. Hauptgrund ist dabei, quasi einen eigenen Namensraum für alle Controller Instanzen zu haben. Um nun vom ControllerManager auf den "globalen" ServiceManager zugreifen zu können, musst du diese eine Ebene hochsteigen. Neben den Controllern gibt es auch weitere ServiceManager z.B. für View-Helper, Controller-Plugins, usw. Neu ab dem 2.2.0 sind auch weitere ServiceManager für Filter, Validatoren und InputFilter.

    HTH,

    Ralf

  17. #17
    Benutzer
    Registriert seit
    29.09.2011
    Beiträge
    45
    Thanks
    0
    Thanked 10 Times in 4 Posts

    Standard

    Hallo Ralf,

    bzgl. "getServiceLocator()" und "getTarget()" vs. "getApplication()": Gibt es hier eine Regel oder Übersicht, wann bzw. welche Methode genutzt werden muss. D.h. kann man sagen im Controller immer "getServiceLocator()", sonst nicht? Und im Controller und Module.php immer "getApplication()", sonst "getTarget()"?

    Bzgl. eigenem Listener: Habe einen eigenen Event nun als Listener mittels SharedListenerAggregateInterface implementiert und entsprechend in der "onBootstrap()" gesetzt.

    Funktioniert zwar alles, habe aber irgendwie nicht kapiert, welche Id als erster Parameter verwendet werden sollte. Für mich unlogisch eine Id zu nutzen, möchte den Event doch in allen Controllern nutzen. Habe deshalb etwas recherchiert und einfach die Id "Zend\Stdlib\DispatchableInterface" genutzt.

    Module.php:
    PHP-Code:
    public function onBootstrap(MvcEvent $e)
    {
        
    $application $e->getApplication();
        
    $sm $application->getServiceManager();
        
    $eventManager $application->getEventManager();
        
    $eventManager->attachAggregate(new AlbumRequestListener($sm->get('AlbumLogger')));
        
    $eventManager->getSharedManager()->attachAggregate(new AlbumAlertListener($sm->get('AlbumLogger')));

    Listener:
    PHP-Code:
    class AlbumAlertListener implements SharedListenerAggregateInterface
    {
        protected 
    $listeners = array();
        protected 
    $logger NULL;

        public function 
    __construct($logger)
        {
            
    $this->logger $logger;
        }

        public function 
    attachShared(SharedEventManagerInterface $events)
        {
            
    $this->listeners[] = $events->attach('Zend\Stdlib\DispatchableInterface''AlbumAlert', array($this'logAlert'));
        }

        public function 
    detachShared(SharedEventManagerInterface $events)
        {
            foreach (
    $this->listeners as $index => $listener)
            {
                if (
    $events->detach('Zend\Stdlib\DispatchableInterface'$listener))
                {
                    unset(
    $this->listeners[$index]);
                }
            }
        }

        ...

    Viele Grüße

    Alex

  18. #18
    Erfahrener Benutzer Avatar von Ralf
    Registriert seit
    14.12.2006
    Beiträge
    450
    Thanks
    0
    Thanked 47 Times in 37 Posts

    Standard

    Hallo Alex,

    eine Regel oder Übersicht, die 100% passt, gibt es nicht. Je nachdem, welche IDE du verwendest, kannst du aber durch die Codevervollständigung in der Regel schauen, welche Methoden bei dem entsprechenden Objekt zur Verfügung stehen. Klappt natürlich nicht, wenn du Objekte aus einem der Service-Manager anforderst.

    Generell ist es so, dass du die zusätzliche Ebene mit getServiceLocator() bei allen spezialisierten Service-Managern benötigst (Controller, Controller-Plugins, View-Helper, InputFilter, Filter, Validator, usw.). Bei dem Haupt-Service-Manager musst du diese Ebene nicht nach oben gehen. Eine kleine Übersicht des Haupt-Service-Managers ("service_manager") und den spezialisierten Service-Managern, die auch konfigurierbar sind, findest du hier:

    https://github.com/zendframework/zf2...actory.php#L35

    getTarget() und getApplication() steht eigentlich nur in den Event Listenern zur Verfügung bzw. überall dort, wo ein Event-Objekt übergeben wird. Wenn du da auf den Service-Manager zugreifen möchtest, musst du z.B. beim MvcEvent erst getApplication() aufrufen, um dann getServiceManager() aufzurufen.

    Die ID beim attach ist der Identifier der Klasse, dem der Event-Manager zugeordnet ist, den du nutzen möchtest. Für alle Controller, die auf den SharedEventManager zugreifen möchten, wird automatisch das "Zend\Stdlib\DispatchableInterface" als Identifier verwendet:

    https://github.com/zendframework/zf2...oller.php#L160

    Gruß,

    Ralf

Ähnliche Themen

  1. Kapitel 4.4 Zend\Log
    Von Alex.Mod im Forum Zend Framework 2 Buch
    Antworten: 8
    Letzter Beitrag: 02.05.2013, 17:55
  2. Codebeispiel Blog Kapitel 16 interner Server-Fehler
    Von hasenfreund im Forum Zend Framework 2 Buch
    Antworten: 2
    Letzter Beitrag: 15.04.2013, 22:53

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •