Ankündigung

Einklappen
Keine Ankündigung bisher.

Allgemeine Fragen zum (Rich) Domain Model

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Allgemeine Fragen zum (Rich) Domain Model

    Hallo,

    ich versuche gerade das "Rich Domain Model" zu verstehen, und hätte dazu noch ein paar Fragen, auf die ich selber nicht eine geeignete Antwort finde. Ich werde zunächst die wichtigen Begriffe selbst zusammenfassen, um zu sehen ob ich auch wirklich die Theorie verstanden habe und komme dann zu meinen Fragen.

    So wie ich es verstanden habe, sind "Rich Domain Models" Modelle, die den Zustand (Attribute) und das Verhalten eines Modells (Methoden, die auf Zustände und andere Modelle zugreifen) vereinigen. Diese Modelle haben den Vorteil, dass man aus ihnen sehr komplexe Anwendungen bauen kann. In ihnen findet die komplette Business-Logik statt und ist zusammen "das Herz der Anwendung".

    Business-Logik finde ich schwer zu definieren. Die Business-Logik gibt der Anwendung Funktionalität, sie gibt ihr "Leben". Sie kümmert sich darum, Daten zu verarbeiten (Berechnungen, ...) und aus ihnen logische Zusammenhänge zu bilden.

    Das krasse Gegenteil zum "Rich Domain Model" ist das "Anemic Domain Model". Hier werden Modelle nur als Datenbehälter verwendet und jede einzelne Funktion wird in anderen Klassen ausgelagert, die dann auf diese Datenbehälter zugreifen und sie manipulieren, etc. können. Dieses Prinzip ist wohl sehr beliebt, weil manche Anwendungen keine hohe Komplexität aufweisen und man nach diesem Prinzip "einfach" programmieren kann. Ein Problem wird es, wenn die Anwendung an Komplexität gewinnt und sie langsam aber sicher immer unübersichtlicher wird und schwerer zu warten.

    Von wo ein Modell nun seine Daten herbekommt, darf es nicht wissen. Dafür sind Data-Mapper zuständig, die Daten aus einer Quelle (DB, etc...) holen und dem Modell übergeben.

    Möchte man Methoden schreiben, die zu keinem Modell richtig passen, bietet es sich an, Service-Klassen zu schreiben, die dann einzelne Methoden der Modelle aufrufen und sie zusammenfügen. Die Methoden der Service-Klasse sollten sich aber bemühen, keine Business-Logik zu definieren, sondern sich nur um das Koordinieren der einzelnen Methoden der Modelle zu kümmern.

    1. Frage: Wie oben beschrieben, sollte man Rich Domain Models nur verwenden, wenn man weiß, dass die Anwendung sehr komplex wird. Was macht man aber, wenn die Anwendung sowohl primitive Datenbank-Abfragen enthält, und an einer anderen Stelle sehr komplex werden kann?
    Ich würde sagen, dass man dann trotzdem versuchen sollte, Rich Domain Models zu entwickeln und dann eben an den einen Stellen nur Daten durch Getter-Methoden holt und sie darstellt. Dann gäbe es zwar "bags of getters and setters" (Martin Fowler) aber eine Alternative gibt es nicht, und es stört auch nicht, oder?

    2. Frage: Wie steht ihr dazu, Getter und Setter zu verwenden? An manchen Stellen lese ich, dass man Setter und Getter auf jeden Fall nutzen sollte, da man durch Setter zum Beispiel prüfen kann, ob die eingegeben Werte Sinn machen. Andere meinen, dass man gar nicht Getter und Setter verwenden sollte (das war glaub ich nur ein Kommentar eines Blogeintrags, aber ich kann mir das nicht richtig vorstellen, wie das dann funktionieren soll).

    3. Frage: Diese Frage ist ein bisschen länger, und zwar komme ich nicht ganz mit der Navigation der Klassen klar.
    Ich möchte die Frage mit einem Beispiel genauer definieren. Angenommen wir haben ein Blog (ja, das Blog-Beispiel), ich habe mal was kleines zusammengebastelt, darum bin ich mir sicher, dass das diagramm nicht 100% korrekt ist, aber das wäre jetzt so, wie ich es machen würde:



    Ich würde jetzt behaupten, dass die Richtungen der Assoziationen in beide Richtungen verlaufen, da man zum einen mehrere Einträge eines Autors anzeigen lassen möchte (eine Liste von Einträgen-Objekten?), aber man auch ein einzelnen Eintrag eines Autors anzeigen lassen möchte, und der dann natürlich den Autornamen darstellen soll (über ein Autor-Objekt?).
    Kann man das so sagen, oder liegt hier ein Denkfehler vor?

    4. Frage: (bezieht sich auf das Beispiel von oben) Habe ich die Methoden zum hinzufügen eines Eintrags richtig angeordnet/Kommt sowas in die Autor-Klasse?
    Die Klassen würden ungefähr so aussehen:

    PHP-Code:
    class Autor 
    {
        protected 
    id;
        protected 
    name;
        protected 
    passwort;
        protected 
    wohnort;
        protected 
    Eintraege = array();
        
    //getter und setter, alle public
        
    public function changePassword($alt$neu$wiederholung);    //prüfen, ob $neu und $wiederholung gleich ist und ob $alt mit $this->passwort übereinstimmt
        
    public function localizeWohnort(); //gibt koordinaten vom wohnort zurück
        
    public function saveEintrag(Eintrag $eintrag); //fügt neuen eintrag hinzu
        
    public function removeEintrag(Eintrag $eintrag); //löscht ihn.
    }

    class 
    Eintrag 
    {
        protected 
    id;
        protected 
    ueberschrift;
        protected 
    text;
        protected 
    autor;
        
    //getter und setter, setter könnten überprüfen, ob überschrift mind. 5 und max. 40 zeichen enthällt
        
    public function findAdvertisment() //liefert url, die zur werbung führt
        
    public function createUrl() //erstellt aus id und überschrift eine schöne url

    5. Frage: Wo und wie "verbindet" man den Data-Mapper mit einem (Rich) Domain Model? Beziehungsweise: Wie kann der Mapper jetzt genau Einträge speichern? Ich stell mir das gerade so vor im Controller (oder auch ein Service mit dem Namen "createNeuenEintrag" um den Controller dünn zu halten?):

    PHP-Code:
    $autorMapper = new AutorMapper();
    $autor $autorMapper->find(3);    //wir haben von irgendwo die id her
    $eintrag = new Eintrag();
    $eintrag->setUeberschrift('foo')
            ->
    setText('viel text');
    $autor->addEintrag($eintrag);
    $autorMapper->save($autor); 
    Aber irgendwie hab ich ein sehr schlechtes Gefühl dabei, oder mir ist das mit dem Rich Domain Modell doch noch nicht so ganz klar. Könnte so eine Implementierung aussehen? Falls das Müll ist, wie könnte man das besser machen (gerne auch mit einem anderen Beispiel, da ein Eintrag hinzuzufügen ja doch nicht soo komplex ist).

    Auch kann ich mir grad nicht richtig vorstellen, wie die Save-Methode des AutorMappers() genau den neuen Eintrag speichern soll. Sie könnte alle Einträge, die im Array von "Autor" sind durchgehen und in der DB updaten, aber das ist doch quatsch.

    6. Frage: Frage zur Methodik: Wie kommt man vom "Datenbank-Denken" weg? Wenn ich versuche ein Modell zu designen, überlege ich automatisch immer: Was möchte ich in der DB speichern? Dementsprechend sind dann auch die Eigenschaften dieses Modells. Gibt es da bessere Möglichkeiten?

    Auf meiner To-Read Liste steht auf jeden Fall der Martin:http://www.amazon.de/Patterns-Enterp...pr_product_top

    Ich glaub man kann sehen, dass viel Verwirrung herrscht

    Beste Grüße, und schonmal Danke für die Antworten
    filipre

  • #2
    Zu der Frage Rich Models oder nicht denke ich immer, es kann nicht gut sein, wenn eine Klasse zu viele Aufgaben übernimmt.

    Dementsprechend sind dann auch die Eigenschaften dieses Modells.
    Die Frage ist doch, wie die Eigenschaften sonst strukturiert sein sollten? Du wirst doch z. B. für einen Autor immer Name, Vorname, etc. haben, oder? Und ob Du diese Daten in einer DB, einer xml-Datei oder über einen Web-Service speichern willst, ist doch letzten Endes nur eine Frage der Datenhaltung..

    Kommentar


    • #3
      Also ich habe bisher erst gar nicht zwischen Rich- und Anemic-Domänenmodellen unterschieden. In den meisten Fällen bestehen meine Domain-Objects aus Attributen (protected) sowie dazugehörigen Setter- & Getter-Methoden. Braucht ein Domain-Model noch zusätzliche Funktionalität, dann bekommt es diese auch in Form einer Methode. Wobei man hier natürlich prüfen sollte, ob diese Funktionalität nicht in einer seperaten Klasse besser aufgehoben wäre. Die Eintrag::createUrl()-Methode sollte bspw. ein weiteres Domain-Model nutzen, welches eine URL repräsentiert.

      PHP-Code:
      class Eintrag
      {
          
      // ...

          
      public function createUrl()
          {
              
      $URL $this->getServiceManager()->get('url-domain-object');
              
      $URL->setSheme('http');
              
      $URL->setHost('website.org');
              
      $URL->mergeQuery(array('title' => $this->getTitle()));
              return 
      $URL;
          }

          
      // ...


      2. Frage: Wie steht ihr dazu, Getter und Setter zu verwenden? An manchen Stellen lese ich, dass man Setter und Getter auf jeden Fall nutzen sollte, da man durch Setter zum Beispiel prüfen kann, ob die eingegeben Werte Sinn machen. Andere meinen, dass man gar nicht Getter und Setter verwenden sollte (das war glaub ich nur ein Kommentar eines Blogeintrags, aber ich kann mir das nicht richtig vorstellen, wie das dann funktionieren soll).
      Manche verzichten auf setter und getter und arbeiten direkt mit den Klassen-Eigenschaften:
      PHP-Code:
      class Eintrag
      {
          public 
      $title;
          public 
      $content;
          public 
      $creationTimestamp;
      }

      $eintrag = new Eintrag;
      $eintrag->title 'Erster Blogeintrag'
      Eigenschaften von Domain-Models würde ich aber immer vor dem öffentlichen Zugriff schützen und dafür has*, is* und get* Methoden anbieten, die ein Ergebnis anhand des Wertes eines Klassen-Attributes zurückliefern.

      Nehmen wir an, Blog-Einträge werden in einer Tabelle eines RDBMS abgebildet, welche über die Spalte published mit dem Datentyp Tinyint verfügt. Felder dieser Spalte können als Wert entweder 1 (veröffentlicht) oder 0 (nicht veröffentlicht) annehmen. Mittels ORM oder TableGateway-Implementierung befüllst Du nun das Domänenmodell Eintrag.

      In der Klasse Eintrag definierst Du nun:
      PHP-Code:
      <?php
      class Eintrag
      {
          protected 
      $id 0;
          protected 
      $title '';
          protected 
      $content '';
          protected 
      $published 0;

          public function 
      setPublished($published)
          {
              
      $this->published intval($published);
          }

          public function 
      isPublished()
          {
              return 
      $this->published === true false;
          }
      }
      In einem Controller oder sonst wo musst Du nun nicht wissen, welchen Wert die Klassenvariable $published benötigt, damit ein Eintrag als veröffentlicht gilt - du erhälst über isPublished() einen Wahrheitswert und das wars. Wenn Du jetzt aber stattdessen an mehreren Stellen folgendes stehen hast..
      PHP-Code:
      if ($entry->published === 1) {
          
      // ...

      ...und vielleicht später mal die Spalte published von Tinyint auf Varchar umstellst, dann wirst Du den direkten Zugriff auf Klassen-Attribute bereuen, da Du dir an verschiedenen Stellen Abhängigkeiten zu dem Datentyp (Tiny)int geschaffen hast.
      Es zahlt sich immer aus, get* oder is* Methoden dem direkten Zugriff auf Klassen-Eigenschaften vorzuziehen, auch wenn diese keine zusätzliche Logik implementieren. Sollte es nämlich irgendwann doch mal notwendig sein, die Return-Werte zu manipulieren, dann hast Du durch den zusätzlichen Zwischenschritt (Getter-Methode) die Möglichkeit dazu.


      4. Frage: (bezieht sich auf das Beispiel von oben) Habe ich die Methoden zum hinzufügen eines Eintrags richtig angeordnet/Kommt sowas in die Autor-Klasse?
      Wieso verfügt die Auto-Klasse über eine Methode zum speichern eines Eintrags? Erstens gehört die Methode saveEintrag() wenn schon in die Klasse Eintrag, zweitens sollte ein Domänen-Modell m.M.n überhaupt nicht wissen, wo und wie es persistiert wird.

      Bei mir würde der Ablauf ungefähr so aussehen:
      1) Controller besorgt sich ein Form-Object (repräsentiert ein (HTML)-Formular, beinhaltet auch Filter und Validatoren)
      2) Controller übergibt die Daten des Form-Objects dem Domain-Model
      3) Controller holt sich eine Instanz einer Repository-Klasse
      4) Controller übergibt das gefüllte Domain-Model dem Repository und ruft bspw. Repository::save() auf.
      5) Repository::save() greift auf einen ORM zu und übergibt diesem das Domain-Model
      6) ORM speichert Daten des Domain-Models in einem RDBMS.

      Das Repsitory ist die einzige Stelle, die darüber bescheid weiß, wo ein Domain-Model gespeichert wird.
      Damit sollte wohl auch Frage 5 beantwortet sein.



      6. Frage: Frage zur Methodik: Wie kommt man vom "Datenbank-Denken" weg? Wenn ich versuche ein Modell zu designen, überlege ich automatisch immer: Was möchte ich in der DB speichern? Dementsprechend sind dann auch die Eigenschaften dieses Modells. Gibt es da bessere Möglichkeiten?
      Was spricht denn gegen diese Denkweise?

      Kommentar


      • #4
        Die Frage ist doch, wie die Eigenschaften sonst strukturiert sein sollten? Du wirst doch z. B. für einen Autor immer Name, Vorname, etc. haben, oder? Und ob Du diese Daten in einer DB, einer xml-Datei oder über einen Web-Service speichern willst, ist doch letzten Endes nur eine Frage der Datenhaltung..
        Ah, also kann man durchaus so seine Modelle gestalten? Meine Befürchtung war, dass eben dadurch die Klassen zu reinen Datenbehältern werden. Auch habe ich gelesen, dass oftmals Domänen Klassen von den Datenbanken (stark) abweichen können, deswegen war ich vielleicht auch etwas verwundert.

        PHP-Code:
        $URL->mergeQuery(array('title' => $this->getTitle())); 
        Ist mergeQuery() dafür verantwortlich, dass die die Datenquelle (DB, etc.) geupdatet wird?
        Da wirft sich für mich jetzt noch eine Frage auf: Ist es okey, wenn Methoden aus einem Modell auf einen Data-Mapper zugreifen? Ich dachte vorhin noch, dass man eher "Speichern, Löschen, etc." im Controller oder einem Service machen sollte, aber es spricht ja nix dagegen, dies auch in einem Modell zu machen, solang man dies über ein Mapper macht, damit man unabhängig bleibt, richtig?

        Es zahlt sich immer aus, get* oder is* Methoden dem direkten Zugriff auf Klassen-Eigenschaften vorzuziehen, auch wenn diese keine zusätzliche Logik implementieren. Sollte es nämlich irgendwann doch mal notwendig sein, die Return-Werte zu manipulieren, dann hast Du durch den zusätzlichen Zwischenschritt (Getter-Methode) die Möglichkeit dazu.
        Das hört sich gut an, danke.

        Wieso verfügt die Auto-Klasse über eine Methode zum speichern eines Eintrags?
        Ich hab da ein bisschen an dieses Beispiel mit der Order-Klasse und der OrderItem-Klasse gedacht. Dort werden die Items über eine addItem-Methode der Order-Klasse in der selbigen gespeichert (in einem Liste). Vielleicht kannst du mir erläutern, wieso dort das so gewählt wurde? Gerne können wir auch das Beispiel anstatt dem Blog-Beispiel nehmen.

        Bei mir würde der Ablauf ungefähr so aussehen: [...]
        Genau so habe ich mir das auch überlegt und anfangs auch so geschrieben. Allerdings machte mich dann doch der Artikel von Fowler etwas stutzig und dann doch noch ein paar Fragen aufkamen.
        Zu deinem Ablauf würde mir vielleicht auch so ein Ablauf einfallen (siehe auch weiter oben, dein Beispiel, das ich so auch verstanden habe):

        1. Controller besorgt sich ein Form-Object (repräsentiert ein (HTML)-Formular, beinhaltet auch Filter und Validatoren)
        2. Controller übergibt die Daten des Form-Objects dem Domain-Model
        3. Domain-Model ruft "save" Methode auf
        4. Save-Methode greift auf einen Data-Mapper zu
        5. Der Data-Mapper kümmert sich darum, wie und wo das Objekt gespeichert werden soll

        Wäre auch sowas denkbar oder sollte ein Modell nicht auf ein Data-Mapper zugreifen können?

        Was spricht denn gegen diese Denkweise?
        siehe oben.

        Kommentar


        • #5
          Da wirft sich für mich jetzt noch eine Frage auf: Ist es okey, wenn Methoden aus einem Modell auf einen Data-Mapper zugreifen? Ich dachte vorhin noch, dass man eher "Speichern, Löschen, etc." im Controller oder einem Service machen sollte, aber es spricht ja nix dagegen, dies auch in einem Modell zu machen, solang man dies über ein Mapper macht, damit man unabhängig bleibt, richtig?
          Wenn du es im Model machst ist es nicht unabhängig.
          Ein Model weiß nichst von der Existenz eines Mappers.

          Das hört sich gut an, danke.
          Der Einfachkeit halber implementiert man idR die MagicMethods, welche widerum die Getter/Setter aufrufen.
          Ein $object->name is halt doch schöner als $object->getName().
          Wichtig dabei ist allerdings, dass die Properties nicht existieren dürfen, sonst greifen die MMs nicht.
          Das ist auc hmit ein Grund, weshalb man private/protected Properties im Normalfall mit einem Unterstrich beginnen lässt.

          Ich hab da ein bisschen an dieses Beispiel mit der Order-Klasse und der OrderItem-Klasse gedacht. Dort werden die Items über eine addItem-Methode der Order-Klasse in der selbigen gespeichert (in einem Liste). Vielleicht kannst du mir erläutern, wieso dort das so gewählt wurde? Gerne können wir auch das Beispiel anstatt dem Blog-Beispiel nehmen.
          Das ist keine Speicherung im eigentlichen Sinne.
          Irgendwo müssen die Beziehungsdaten ja vorgehalten werden, hier eben in einer Liste.
          Das tatsächliche Speichern erfolgt erst später in einem Mapper.

          3. Domain-Model ruft "save" Methode auf
          4. Save-Methode greift auf einen Data-Mapper zu
          Nein!
          Genau da schaffst du dir ja die Abhängigkeit.
          Controller befüllt Model
          Controller übergibt Model an Service/Repository
          [Service übergibt model an Repository]
          Repository übergibt Model an Mapper
          Mapper mappt Daten ins passende DAO

          Aus eigener Erfahrung gebe ich dir den Tipp, PoEAA erstmal ganz durchzuarbeiten bevor du dich an die Implementation eines kompletten Model-Frameworks machst.
          Dir begegnen da noch viele nette Sachen von LazyLoading bis DependencyInjection, die in der ganzen Geschichte überaus hilfreich sind.
          VokeIT GmbH & Co. KG - VokeIT-oss @ github

          Kommentar


          • #6
            Ist mergeQuery() dafür verantwortlich, dass die die Datenquelle (DB, etc.) geupdatet wird?
            Da wirft sich für mich jetzt noch eine Frage auf: Ist es okey, wenn Methoden aus einem Modell auf einen Data-Mapper zugreifen? Ich dachte vorhin noch, dass man eher "Speichern, Löschen, etc." im Controller oder einem Service machen sollte, aber es spricht ja nix dagegen, dies auch in einem Modell zu machen, solang man dies über ein Mapper macht, damit man unabhängig bleibt, richtig?
            merge = verschmelzen. Damit ist gemeint, dass der aktuelle Query (bspw. ?controller=foo&action=baz) mit dem per mergeQuery() übergebenen Query verschmolzen wird.
            Und zu den weiteren Fragen bzgl. Mapper in DO's hat Schuster ja bereits alles gesagt.

            Wichtig ist, dass Du den Schritt:
            Zitat von G.Schuster
            Controller übergibt Model an Service/Repository
            nicht auslässt. Wie Du diese Services nennst, spielt keine große Rolle. In FLOW3 und anderen nennt man sie eben Repository. Manchmal verwendet man auch Manager-Klassen, die, wie Repositories DO's entgegen nehmen und per Mapper in der DB speichern.

            Habe hier gerade ein nettes Tutorial gefunden: http://flow3.typo3.org/documentation...epository.html
            Hier siehst Du auch, wie Blog-Einträge mit einem Blog und Kommentare mit einem Blog-Eintrag assoziiert werden. (genau so wie in deinem Order & OrderItem Beispiel, nur halt in PHP).

            Kommentar


            • #7
              Nur zur Klarstellung: ein Repository ist etwas vollkommen anderes als ein Service.
              Ein Service kann durchaus Zugriff auf mehrere Repositories haben und damit auch eine gewisse Business-Logik implementieren, ein Repository hingegen verwaltet ausschließlich eine Art von Model und ist unter Anderem dafür zuständig, dass eine Model-Instanz zur Laufzeit auch nur einmal geladen wird.
              VokeIT GmbH & Co. KG - VokeIT-oss @ github

              Kommentar


              • #8
                Danke nochmals für die Antworten

                Wenn du es im Model machst ist es nicht unabhängig.
                Ein Model weiß nichst von der Existenz eines Mappers.
                okey, dann ist das jetzt für mich klar.

                Ein $object->name is halt doch schöner als $object->getName().
                Da könnte man jetzt eine ganze Diskussion (die denk ich auch schon öfters geführt wurde?) halten schätz ich Da ist wohl jeder frei, wie man genau dann die Getter und Setter (oder auch nicht) implementiert. Aber die Frage hat sich daher dann auch geklärt.

                Habe hier gerade ein nettes Tutorial gefunden: http://flow3.typo3.org/documentation...epository.html
                Hier siehst Du auch, wie Blog-Einträge mit einem Blog und Kommentare mit einem Blog-Eintrag assoziiert werden. (genau so wie in deinem Order & OrderItem Beispiel, nur halt in PHP).
                Das ist ein schönes Bespiel, und auf der Website steht auch Vieles beschrieben. Trotzdem habe ich noch nicht ganz 100% verstanden, wie das Speichern (eines Eintrags bspw.) dort stattfindet.

                Im Controller dieser Anwendung gibt es zum Beispiel die "createAction()" die dafür zuständig ist, dass der Eintrag/Post gespeichert wird.
                PHP-Code:
                public function createAction(\TYPO3\Blog\Domain\Model\Post $newPost) {
                        
                $this->postRepository->add($newPost);
                        
                $this->blog->addPost($newPost);
                        
                $this->blogRepository->update($this->blog);
                        
                $this->addFlashMessage('Your new post was created.');
                        
                $this->redirect('index');
                    } 
                Die "PostRepository-Klasse" ist ja dafür zuständig, Einträge zu finden, löschen und auch zu speichern. Dementsprechend nimmt die "add-Methode" dann auch als Parameter ein Post-Objekt. Sie fügt also (wenn wir eine DB haben) einen neuen Eintrag in die Tabelle Post ein.
                Wenn bereits die PostRepository-Klasse dafür sorgt, Einträge hinzuzufügen, wieso wird dann nochmal im Blog-Objekt der Eintrag hinzugefügt, und dann die Update-Methode mit dem Blog-Objekt aufgerufen? Was wird da "geupdatet", schließlich befindet sich doch schon der neue Eintrag in der Tabelle? Oder bewirkt die update-Methode noch etwas anderes?

                Nur zur Klarstellung: ein Repository ist etwas vollkommen anderes als ein Service.
                Ein Service kann durchaus Zugriff auf mehrere Repositories haben und damit auch eine gewisse Business-Logik implementieren, ein Repository hingegen verwaltet ausschließlich eine Art von Model und ist unter Anderem dafür zuständig, dass eine Model-Instanz zur Laufzeit auch nur einmal geladen wird.
                Danke für den Hinweis!

                Beste Grüße

                Kommentar


                • #9
                  Zitat von filipre Beitrag anzeigen
                  PHP-Code:
                  public function createAction(\TYPO3\Blog\Domain\Model\Post $newPost) {
                          
                  $this->postRepository->add($newPost);
                          
                  $this->blog->addPost($newPost);
                          
                  $this->blogRepository->update($this->blog);
                          
                  $this->addFlashMessage('Your new post was created.');
                          
                  $this->redirect('index');
                      } 
                  Die "PostRepository-Klasse" ist ja dafür zuständig, Einträge zu finden, löschen und auch zu speichern. Dementsprechend nimmt die "add-Methode" dann auch als Parameter ein Post-Objekt. Sie fügt also (wenn wir eine DB haben) einen neuen Eintrag in die Tabelle Post ein.
                  Wenn bereits die PostRepository-Klasse dafür sorgt, Einträge hinzuzufügen, wieso wird dann nochmal im Blog-Objekt der Eintrag hinzugefügt, und dann die Update-Methode mit dem Blog-Objekt aufgerufen? Was wird da "geupdatet", schließlich befindet sich doch schon der neue Eintrag in der Tabelle? Oder bewirkt die update-Methode noch etwas anderes?
                  Das wäre ein guter Fall für einen Service.
                  Der nimmt den Post entgegen, speichert ihn über das PostRepository und nimmt noch die Verlinkung gegen das BlogRepository vor.
                  Ich hab das Beispiel jetzt nur mal kurz überflogen und auf die Schnelle keinen Sinn darin gefunden, überhaupt das BlogRepsoitory zu bemühen, zumindest nicht in Form eines Updates.
                  Wenn ich mir das richtig zusammengereimt habe sollte das Repo lediglich eine aktuelle List der Posts vorhalten, ergo Eintrag über das PostRepo erledigen, da ist die Zuordnung zum Blog bereits enthalten, und dann nur ins BlogRepo in einen Container hinzufügen, damit das Objekt auf aktuellem Stand ist.

                  PHP-Code:
                  public function createAction(\TYPO3\Blog\Domain\Model\Post $newPost) {
                          
                  $this->blogService->savePost($newPost);
                          
                  $this->addFlashMessage('Your new post was created.');
                          
                  $this->redirect('index');
                      } 
                  Im Übrigen halte ich nichts von der Unterscheidung zwischen add und update - ein sauberes Domainmodel respektive der zugehörige Mapper kann das anhand der vorliegenden Daten selbst entscheiden.
                  Von daher gibt es in meiner Implementation im ZF nur save, get und remove.


                  Hach...da wollte ich mal nur "kurz" antworten und schon ist's wieder so lang geworden...das Thema lässt sich einfach nicht in aller Schnelle besprechen :-/
                  Ist aber interessant wenn man sich mal wirklich ausführlich damit beschäftigen will.
                  VokeIT GmbH & Co. KG - VokeIT-oss @ github

                  Kommentar


                  • #10
                    Ich hab das Beispiel jetzt nur mal kurz überflogen und auf die Schnelle keinen Sinn darin gefunden, überhaupt das BlogRepsoitory zu bemühen, zumindest nicht in Form eines Updates.
                    Der Meinung bin ich auch.

                    Hach...da wollte ich mal nur "kurz" antworten und schon ist's wieder so lang geworden...das Thema lässt sich einfach nicht in aller Schnelle besprechen :-/
                    Ist aber interessant wenn man sich mal wirklich ausführlich damit beschäftigen will.
                    Das Thema scheint ja auch von vielen unterschiedlichen Faktoren wie "Stiel, Performance, Anforderungen, etc." abzuhängen.

                    Meine 3. Frage bezüglich Assoziationen hat sich übrigens auch geklärt. Da hat mir dieser Thread weitergeholfen.

                    Dann sollte jetzt vieles etwas klarer sein. Super
                    Wie gesagt, Fowler wird gelesen, im Moment fehlt nur die Zeit sich durch 560 Seiten durchzuarbeiten,

                    Beste Grüße,
                    filipre

                    Kommentar


                    • #11
                      Nein, das ergibt keinen Sinn und steht in der Flow3 Doku deswegen auch gar nicht drin

                      Der Code der creationAction():

                      PHP-Code:
                      /**
                       * Creates a new post
                       *
                       * @param \TYPO3\Blog\Domain\Model\Post $post
                       * @return void
                       */
                      public function createAction(\TYPO3\Blog\Domain\Model\Post $newPost) {
                              
                      $blog $this->blogRepository->findActive();
                              
                      $blog->addPost($newPost);
                              
                      $this->postRepository->add($newPost);
                              
                      $this->addFlashMessage('Created a new post.');
                              
                      $this->redirect('index');

                      Mit dem Aufruf von $this->postRepository->add() wird der Post persistiert. Über $blog->addPost() wird davor noch eine Beziehung zwischen Blog und Post definiert.



                      @Schuster: was soll denn $this->blogService darstellen?

                      Kommentar


                      • #12
                        Zitat von tip-top Beitrag anzeigen
                        Nein, das ergibt keinen Sinn und steht in der Flow3 Doku deswegen auch gar nicht drin
                        Ich hab mich nur auf das hier gepostete Beispiel verlassen.

                        Zitat von tip-top Beitrag anzeigen
                        @Schuster: was soll denn $this->blogService darstellen?
                        Einen Service!?
                        Siehe PoEAA Seite 133 ff., Kapitel "Service Layer" ./. Seite 322 ff., Kapitel "Repository".
                        VokeIT GmbH & Co. KG - VokeIT-oss @ github

                        Kommentar


                        • #13
                          Nein, das ergibt keinen Sinn und steht in der Flow3 Doku deswegen auch gar nicht drin
                          Ich hab mir das komplette Blog-Beispiel heruntergeladen, hier: http://git.typo3.org/FLOW3/Packages/TYPO3.Blog.git
                          Und dort habe ich die create-Methode 1:1 kopiert.

                          Kommentar

                          Lädt...
                          X