Ergebnis 1 bis 4 von 4

Thema: Symfony: Allgemeine Fragen zu Services

  1. #1
    Contao-Fan Avatar von lomex
    Registriert seit
    03.07.2009.
    Ort
    Werne
    Beiträge
    791
    User beschenken
    Wunschliste

    Standard Symfony: Allgemeine Fragen zu Services

    Ich arbeite mich gerade in Contao 4 und Symfony ein.
    Generell bleibe ich immer hängen bei der Frage, wann ich Services einsetzen soll?

    Services haben ja den Vorteil, dass ich die Klassen leichter testen kann, in denen ich Services über den Konstruktor übergebe.
    Nur viele Klassen verwenden hart verdrahtete Klasse per use. Siehe z.B. das Calender-Bundle und den GeneratePageListener.
    Ist nur ein Beispiel.

    Generell die Frage, wann sollte ich Services einsetzen?

    In diesem Beispiel gibt es einen Service und einen DataContainer. Warum doppelt gemoppelt? Was würde dagegen sprechen, alles in den Service zu packen?

    Sollte nicht im Prinzip fast alles (außer die Controller und Events, die mir gerade einfallen) Services sein?

  2. #2
    Contao-Urgestein
    Registriert seit
    29.10.2009.
    Ort
    Magdeburg
    Beiträge
    2.020
    Partner-ID
    626
    User beschenken
    Wunschliste

    Standard

    Zitat Zitat von lomex Beitrag anzeigen
    Ich arbeite mich gerade in Contao 4 und Symfony ein.
    Generell bleibe ich immer hängen bei der Frage, wann ich Services einsetzen soll?

    Services haben ja den Vorteil, dass ich die Klassen leichter testen kann, in denen ich Services über den Konstruktor übergebe.
    Soweit es sich um einen Service handelt, würde ich Services bevorzugen. Services sollten zustandslos sein. D.h. wenn du diesen mehrfach aufrufst, sollte er sich gleich verhalten.

    Ob jetzt die Abhängikieten über den Konstruktur injected werden oder per Method Call, hängt davon ab ob die Abhängigkeit notwendig ist. Da du als Nutzer eines Services darauf vertrauen können sollst, dass dieser funktioniert, sind alle Abhängigkeiten im Konstruktor zu übergeben. Optionale Abhängigkeiten würde ich per Methode setzen. Alternativ, falls man unterschiedliche Optionen unterstützen möchte, kann die Abhängigkeit der Methode mitgegeben werden, die diese benötigt:

    PHP-Code:
    // Constructor injection
    $repository = new MyRepository($databaseConnection);

    // Optionale Abhängigkeit
    $repository->setLogger($logger);

    // Dependency Injection per Method call.
    $model->changePassword('mySecretPasswort'$hashGenerator); 
    Zitat Zitat von lomex Beitrag anzeigen
    Nur viele Klassen verwenden hart verdrahtete Klasse per use. Siehe z.B. das Calender-Bundle und den GeneratePageListener.
    Ist nur ein Beispiel.
    Die Codebase von Contao ist (noch) nicht soweit, dass Sie als Best Practise gesehen werden kann. Oder etwas entschärft. Alle Klassen die unter src/Resources/contao liegen, würde ich nicht als Beispiele verwenden. Auch bei dem neuen Code gibt es ein paar Sachen, wo nicht alles sauber ist. Eine harte Verdrahtung ist dann z.b. sinnvoll, wenn du weißt, dass du immer diese Klasse nutzen möchtest. Sonst würde ich Depdendency Injection nutzen.

    Zitat Zitat von lomex Beitrag anzeigen
    Generell die Frage, wann sollte ich Services einsetzen?

    In diesem Beispiel gibt es einen Service und einen DataContainer. Warum doppelt gemoppelt? Was würde dagegen sprechen, alles in den Service zu packen?

    Sollte nicht im Prinzip fast alles (außer die Controller und Events, die mir gerade einfallen) Services sein?
    Wie oben schon genannt, würde ich möglichst vieles in Service laden. Ja, soweit wie möglich würde ich alles registrieren. Ausgeschlossen sind datenbezogene Objekte (DTOs, Events, Models, Commands (ich meine keine Symfony CLI-Commands)). Selbst Controller registriere ich als Service.

    In Contao 4 kann man auch Hooks und DataContainer Callbacks als Services registrieren.

    Grundsätzlich sollte man Klassen so konzipieren, dass Sie einen Zweck dienen. Ich tendiere inzwischen dazu für jeden einzelnen Hook eine Listener Klasse zu implementieren. Manchmal splitte ich auch die DataContainer Callback Klassen um an den oben genannten Beispielen zu bleiben.

    Vielleicht hilft dir das weiter.

  3. #3
    Contao-Fan Avatar von lomex
    Registriert seit
    03.07.2009.
    Ort
    Werne
    Beiträge
    791
    User beschenken
    Wunschliste

    Standard

    Ja, hat auf jedenfall weitergeholfen.

    Nur selbst das Symfony Bundle hat viele use Anweisungen. Nehmen wir z.B. die FrameworkBundle/Routing/Router.php.
    Da gibt es 10 use Anweisungen. Das sind doch feste Abhängigkeiten, oder?

    Ein weiteres Beispiel, wo ich Verständnisschwierigkeiten habe:
    Ich injiziere Doctrine als Service. Austauschen gegen eine andere DB Klasse als Service wird schwerlich gehen, da sie vermutlich nicht die gleichen Methoden verwenden. Also mache ich das "nur", um es per PHPUnit testen zu können, richtig?

  4. #4
    Contao-Urgestein
    Registriert seit
    29.10.2009.
    Ort
    Magdeburg
    Beiträge
    2.020
    Partner-ID
    626
    User beschenken
    Wunschliste

    Standard

    Zitat Zitat von lomex Beitrag anzeigen
    Ja, hat auf jedenfall weitergeholfen.

    Nur selbst das Symfony Bundle hat viele use Anweisungen. Nehmen wir z.B. die FrameworkBundle/Routing/Router.php.
    Da gibt es 10 use Anweisungen. Das sind doch feste Abhängigkeiten, oder?
    Use-Anweisungen sind an sich nur ein Hinweis, das bestimmte Klassen als Alias zur Verfügung gestellt werden, mit denen interagiert wird. Ob es eine feste Abhängigkeit ist, hängt vom Kontext ab.

    Z.b. gibt es bei der von dir erwähnten Router-Klasse schon mal einige Interfaces. Hier ist also keine Abhängigkeit zu einer realen Implementation gegeben. Selbstverständlich müssen die interagierenden Klassen die Interfaces unterstützen.

    Zitat Zitat von lomex Beitrag anzeigen
    Ein weiteres Beispiel, wo ich Verständnisschwierigkeiten habe:
    Ich injiziere Doctrine als Service. Austauschen gegen eine andere DB Klasse als Service wird schwerlich gehen, da sie vermutlich nicht die gleichen Methoden verwenden. Also mache ich das "nur", um es per PHPUnit testen zu können, richtig?
    Jein. Es geht hier nicht nur um das Testing, aber oftmals ist es der Hauptgrund.

    Nehmen wir aber mal das Beispiel mit der Datenbank-Verbindung.

    In Contao 3.x hast du entweder ein $this->import('Database'); oder ein \Database::getInstance() gemacht. Damit hast du immer auf die eine Datenbankverbindung zugegriffen. Wenn du nun bei deinem Service eine Datenbankverbindung benötigst, greifst du auf die Doctrine DBAL Connection zurück. Da du dies über den Service Container definierst und als Konstruktur Abhängigkeit übergibst, könntest du jetzt sehr leicht eine zweite Datenbankverbindung konfigurieren und deinen Service auf zwei verschiedenen Datenbanken arbeiten lassen. Daher ist es auch nomalerweise keine gute Idee den Container zu injezieren und dann ein $container->get('database_connection') zu machen. Dann kannst du nämlich wieder nicht die Datenbankverbindung tauschen.

    Spinnen wir die Idee mit der austauschbaren Datenquelle weiter. Angenommen dein Service verarbeit News und verschickt dazu Mails an Abonnenten. Wenn du deinem Service "NewsNotifier" nicht die DB Connection mitgibst, sondern die Datenabfrage in ein Repository abstrahierst, bist du flexibel die Datenquelle zu tauschen. Jetzt baust du dir z.B. einen RssReader, der die gleiche API wie dein Datenbank-Repository nutzt und schon kann dein Service auch mit einer anderen Datenquelle umgehen.

    Das ist der Sinn von der ganzen Abstraktion. Flexibel zu bleiben um auf geänderte Anforderungen leicht reagieren zu können. Und auch das Testing, wie du schon sagst.

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Lesezeichen

Lesezeichen

Berechtigungen

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