wake-up-neo.com

Wie kann ich mit Symfony2 auf einen Dienst außerhalb eines Controllers zugreifen?

Ich baue eine Website, die ziemlich stark von einer API eines Drittanbieters abhängig ist. Daher dachte ich, es wäre sinnvoll, den API-Wrapper als Dienst zu verpacken. Allerdings fange ich an, Fälle zu finden, in denen der Zugriff darauf nützlich ist außerhalb eines Controllers wie in einem Entitäts-Repository. Ebenfalls damit verbunden ist es sinnvoll, Zugriff auf Konfigurationswerte außerhalb eines Controllers zu erhalten (wiederum wie in einem Entitäts-Repository).

Kann mir jemand sagen, ob dies möglich ist und wenn nicht, gibt es einen Vorschlag, wie man so vorgehen kann?

danke für jede hilfe

51
pogo

Die Symfony-Distribution hängt stark von der Abhängigkeitsinjektion ab. Das bedeutet, dass Abhängigkeiten normalerweise direkt über den Konstruktor, die Setter oder über andere Mittel (z. B. Reflexion über Eigenschaften) in Ihr Objekt eingefügt werden. Ihr API-Wrapper-Service hängt dann von anderen Objekten Ihrer Anwendung ab.

Allerdings ist es ziemlich schwierig, diesen Service in den Konstruktor eines Entitäts-Repositorys einzuspeisen, da er bereits einige andere Parameter erfordert und ich denke, dass es nicht möglich ist, sie einzufügen, da wir das Repository für eine Entität anfordern.

Sie könnten einen anderen Dienst erstellen, der für die Arbeit verantwortlich ist, die Sie im Entitäts-Repository ausführen sollten. Auf diese Weise können Sie den Entitätsmanager injizieren, der zum Abrufen des Entitäts-Repositorys, des benutzerdefinierten Diensts und eines anderen Diensts verwendet wird, der Ihre Konfigurationswerte enthält (Es gibt andere Möglichkeiten, Konfigurationswerte gemeinsam zu nutzen).

In meinem Anwendungsfall verwende ich einen Facebook-Hilfsdienst, der Facebook-API-Aufrufe einschließt. Dieser Service wird dann dort eingespritzt, wo ich ihn brauche. Mein Entitäts-Repository ist nur für das Ausführen von Datenbankaufrufen verantwortlich und erhält daher nur die erforderlichen Argumente und nicht die gesamte Abhängigkeit. Daher wird der Helfer nicht empfangen, sondern nur die Argumente, die für eine Anfrage erforderlich sind, beispielsweise eine Facebook-Benutzer-ID. Meiner Meinung nach ist dies der Weg, da ich denke, dass das Entitäts-Repository keine Abhängigkeiten von solchen Hilfsobjekten haben sollte.

Hier ein kleines Beispiel mit YAML als Konfiguration:

# app/config/config.yml
services:
  yourapp.configuration_container:
    class: Application/AcmeBundle/Common/ConfigurationContainer
    # You could inject configurations here      

  yourapp.api_wrapper:
    class: Application/AcmeBundle/Service/ApiWrapperService
    # Inject other arguments if needed and update constructor in consequence    

  yourapp.data_access:
    class: Application/AcmeBundle/Data/Access/DatabaseAccessService
    arguments: 
      entityManager: "@doctrine.orm.entity_manager"
      apiWrapperService: "@yourapp.api_wrapper"
      configuration: "@yourapp.configuration_container"

# Application/AcmeBundle/Common/ConfigurationContainer.php
public ConfigurationContainer
{
   public function __construct()
   {
       // Initialize your configuration values or inject them in the constructor
   }
}        

# Application/AcmeBundle/Service/ApiWrapperService.php
public ApiWrapperService
{
   public function __construct()
   {
       // Do some stuff
   }
}

# Application/AcmeBundle/Data/Access/DatabaseAccessService.php
public DatabaseAccessService
{
    public function __construct(EntityManager $entityManager, ApiWrapperService $apiWrapperService, ConfigurationContainer $configuration)
    {
        ...
    }
}

Das at-Zeichen (@) in der Datei config.yml bedeutet, dass Symfony einen anderen Dienst einschleusen soll, dessen ID hinter dem at-Zeichen definiert ist, und nicht eine einfache Zeichenfolge. Für die Konfigurationswerte gibt es, wie bereits gesagt, andere Möglichkeiten, um dasselbe Ziel zu erreichen wie das Verwenden von Parametern oder einer Bündelerweiterung. Mit einer Bundle-Erweiterung können Sie die Konfigurationswerte direkt in der Datei config.yml definieren, und Ihr Bundle würde sie lesen.

Zusammenfassend sollte Ihnen dies die allgemeine Vorstellung vermitteln, dass Sie Services einführen. Hier eine kleine Dokumentationsliste zum Thema. Viele Links verwenden die XML-Service-Definition anstelle der YAML-Definition, aber Sie sollten sie leicht verstehen können.

  1. Symfony Official DI
  2. Artikel von Fabien Potencier zu DI
  3. Richard Millers Artikel zu DI (In seinem Blog finden Sie die anderen DI-Artikel.)

Beachten Sie, dass die von mir angegebene Konfiguration für Beta1 von Symfony2 funktioniert. Ich habe noch kein Update auf Beta2 durchgeführt, daher könnte es sein, dass einige Dinge nicht funktionieren, wie in der Beta2-Version.

Ich hoffe, dies wird Ihnen helfen, eine endgültige Lösung für Ihr Problem zu finden. Zögern Sie nicht, andere Fragen zu stellen, wenn Sie Klarstellungen oder etwas anderes wünschen.

Viele Grüße Matt

74
Matt

Ich würde diese Art von Verhalten in einem Symfony-Dienst (wie einem Manager) einwickeln. Ich würde keine Parameter oder Logik in die Entitätsrepositorys einfügen, da sie hauptsächlich zum Abrufen von Daten mithilfe von Objektmanagerabfragen verwendet werden sollten. Ich würde die Logik in die Dienste einfügen und wenn der Dienst einen Datenbankzugriff erfordert, ruft er das Entitäts-Repository auf, um Daten abzurufen.

0
shacharsol