0

Wenn Sie eine andere Middleware/Objekt in einer Middleware haben Sie eine Fabrik verwenden wieZend Expressive Dependency Injection

namespace App\Somnething; 
use Interop\Container\ContainerInterface; 
class MyMiddlewareFactory 
{ 
    public function __invoke(ContainerInterface $container, $requestedName) 
    { 
     return new $requestedName(
      $container->get(\App\Path\To\My\Middleware::class) 
     ); 
    } 
} 

So MyMiddleware mit \App\Path\To\My\Middleware injiziert worden wäre, und wir würden uns darauf zugreifen können .

Frage: wäre es falsch, die Middleware mit der App selbst oder dem Container zu injizieren? Wie:

namespace App\Somnething; 
use Interop\Container\ContainerInterface; 
use Zend\Expressive\Application; 
class MyMiddlewareFactory 
{ 
    public function __invoke(ContainerInterface $container, $requestedName) 
    { 
     return new $requestedName(
      $container->get(Application::class) 
     ); 
    } 
} 

So wäre es möglich, alles zu bekommen ~ on the fly. Wie

namespace App\Somnething; 
use Zend\Expressive\Application; 
class MyMiddleware 
{ 
    /** @var Application $app */ 
    protected $app; 

    public function __construct(Application $app) 
    { 
     $this->app = $app; 
    } 

    public function __invoke($some, $thing) 
    { 
     if ($some and $thing) { 
      $ever = $this->app 
       ->getContainer() 
       ->get(\Path\To\What\Ever::class); 
      $ever->doSome(); 
     } 
    } 
} 

Antwort

4

Sie injizieren keine Middleware in andere Middleware. Sie injizieren Abhängigkeiten wie Services oder Repositories. Jede Middleware kümmert sich um eine bestimmte Aufgabe wie Authentifizierung, Autorisierung, Lokalisierungsverhandlung usw. Sie werden nacheinander ausgeführt. Sie machen sich mit der Anfrage herum und leiten die Anfrage an die nächste Middleware weiter. Sobald der Middleware-Stack aufgebraucht ist, wird die Antwort in umgekehrter Reihenfolge durch die gesamte Middleware zurückgegeben, bis sie schließlich die äußere Ebene erreicht, die die Ausgabe anzeigt. Eine Flussübersicht finden Sie in der expressive docs.

Ich würde nicht empfehlen, den Container und sicherlich nicht die App selbst zu injizieren. Obwohl es während der Entwicklung einfach sein könnte, wird Ihre Anwendung nicht testbar. Wenn Sie nur die benötigten Dienste in eine Middleware, eine Aktion oder einen Dienst injizieren, können Sie diese während der Tests leicht verspotten. Nach einer Weile gewöhnt man sich daran, Fabriken zu schreiben, wo es gebraucht wird, und es geht ziemlich schnell.

Das gleiche gilt für die Injektion des Entity Managers (wenn Sie Doktrin verwenden). Es ist einfacher, eine Anwendung zu testen, wenn Sie nur die benötigten Repositorys einspeisen, die Sie leicht nachahmen können.

Mit diesen Worten, wenn Sie nach einer einfachen Möglichkeit suchen, Abhängigkeiten zu injizieren, kann zend-servicemanager das tun. Werfen Sie einen Blick auf abstract factories. Mit einer abstrakten Fabrik können Sie eine Fabrik für alle Action-Klassen erstellen:

<?php 

namespace App\Action; 

use Interop\Container\ContainerInterface; 
use ReflectionClass; 
use Zend\ServiceManager\Factory\AbstractFactoryInterface; 

class AbstractActionFactory implements AbstractFactoryInterface 
{ 
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null) 
    { 
     // Construct a new ReflectionClass object for the requested action 
     $reflection = new ReflectionClass($requestedName); 
     // Get the constructor 
     $constructor = $reflection->getConstructor(); 
     if (is_null($constructor)) { 
      // There is no constructor, just return a new class 
      return new $requestedName; 
     } 

     // Get the parameters 
     $parameters = $constructor->getParameters(); 
     $dependencies = []; 
     foreach ($parameters as $parameter) { 
      // Get the parameter class 
      $class = $parameter->getClass(); 
      // Get the class from the container 
      $dependencies[] = $container->get($class->getName()); 
     } 

     // Return the requested class and inject its dependencies 
     return $reflection->newInstanceArgs($dependencies); 
    } 

    public function canCreate(ContainerInterface $container, $requestedName) 
    { 
     // Only accept Action classes 
     if (substr($requestedName, -6) == 'Action') { 
      return true; 
     } 

     return false; 
    } 
} 

Ich schrieb einen blog post darüber.

Am Ende des Tages ist es Ihre eigene Entscheidung, aber die beste Praxis ist nicht die App, den Container oder den Entity Manager. Es wird Ihnen das Leben erleichtern, wenn Sie Ihre Middleware debuggen und/oder Tests dafür schreiben müssen.

+0

Wäre es nicht besser, die Middleware Action durch 'MiddlewareInterface' zu ​​implementieren und' 'canCreate' nach' return in_array ('MiddlewareInterface', class_implements ($ requestedName), true) '' Thanks btw! – cottton

+0

Das ist ja auch möglich. Soweit ich weiß, ist es jedoch sehr teuer, Reflection zu verwenden. Ich möchte nicht alle meine Middleware automatisch initialisieren, nur eine Aktionsklasse pro Anfrage genügt mir. – xtreamwayz

0

in Ihrer Middleware, die Anwendung oder Container Injektion ist möglich, aber es ist nicht gute Idee überhaupt:

1) Inversion of Control (IoC)

Es die Umkehrung des Steuerprinzips verletzt, Ihr Klasse darf kein Wissen über den IoC-Container haben.

2) Dependency Inversion Principle (DIP)

Dependency Inversion Prinzip besagt, dass "High-Level-Module nicht auf Low-Level-Module abhängig gemacht werden soll", so hängt Ihre höhere Ebene Middleware-Klasse auf der Infrastruktur/Rahmen .

3) Gesetz von Demeter (LoD)

Nach dem Gesetz von demeter, die Einheit begrenzte Kenntnisse über andere Einheiten haben sollte, sollte es nur um seine eng verwandten Einheiten kennt.

Die MyMiddleware::class hat zu viel Wissen anderen Einheiten, vor allem, es weiß um die Application::class, dann weiß er, dass die Application weiß um die Container, dann weiß er, dass die Container weiß um die What\Ever::class und so weiter.

Diese Art von Code verletzt einige der wichtigsten OOP-Prinzipien, führt zu schrecklichen Kopplung mit dem Framework, es hat implizite Abhängigkeiten und am wenigsten, aber nicht zuletzt, es ist schwer zu lesen und zu verstehen.