MB: Bild und Text kombiniert verschachteln

moin,

wie kriegt man im MVC-Paradigma Bild und Text unter? Ich habe Tabellen in der Database mit Bilder URL's, Texte und Listen allesamt mit dazugehörigen ID's. Ich hab versucht im Model alle zu kombinieren und es klappt auch, jedoch sprenkt das in diesem Projekt meine ganze Programmierlogik 😕.

lgmb

  1. Hallo MB,

    das ist aber jetzt erstmal kein Problem von Text und Bild.

    MVC bedeutet Model - View - Controller, d.h. Du hast ein DB-nahes fachliches Datenmodell, du hast die Darstellungssicht (view) und Du hast einen oder mehrere Controller, die alles steuern.

    Aber: Niemand sagt, dass das Model 1:1 an der DB hängt. Du kannst die DB-Struktur auch in eine Modellstruktur transformieren, die Dir besser passt.

    Niemand sagt, dass ein Model genau ein Objekt ist - es kann auch eine Objekthierarchie sein.

    Niemand sagt, dass ein View genau ein Objekt ist - es kann ebenfalls eine Objekthierarchie sein.

    Und niemand sagt, dass die Modelhierarchie und die Viewhierarchie gleich strukturiert sein müssen. Es kann praktischer sein, das zu ändern.

    Oder Du erzählst noch was mehr von deiner Problemstellung, mit deinem Universalseufzer kommen wir nicht wirklich weit beim Versuch Dir zu helfen 😀

    Rolf

    --
    sumpsi - posui - clusi
    1. moin,

      Oder Du erzählst noch was mehr von deiner Problemstellung, mit deinem Universalseufzer kommen wir nicht wirklich weit beim Versuch Dir zu helfen 😀

      Du hast recht sry 😕.

      Ein konkretes Anwendungsbeispiel (Ich hoffe es ist verständlich):

      In der meiner Database habe ich die Tabellen tbl_article und tbl_listings. Durch ein Repository RepositiryArticle kriege ich ein Objekt TArticle ohne Liste und Links. Über Das Model ArticleModel, von wo aus ich das Repository instanziiert habe, fügt es in seiner Methode addLink( TArticle $article ) Links zum Objekt TArticle hinzu.

      Soweit so gut. Hinzu kommt noch ein weiteres Repository von der Tabelle $tbl_listing. Das übergibt dem ArticleModel ein TListing Objekt, dass mit der Methode addListing( TArticle $article ) in das TArticle-Objekt integriert wird.

      Ich rufe gleich im Konstruktor selbst eine andere Klasse auf damit ich zugriff auf diese habe, sprich:

      class ArticleController extends Controller {
        public function __constructor() {
          $this->model = new ArticleModel();
        }
      }
      
      class ArticleModel extends Model {
        public function __constructor() {
          $this->repository = new ArticleRepository();
        }
      }
      
      class ArticleRepository extends Repository {
        public function __constructor() {}
      }
      

      Da viel mir ein das ich auch ListingRepository und ebenfalls GalleryRepository brauche um im ArticleModel Grafiken und Listen zu integrieren 😕. Ich hab dann, nach dem Instanziieren von ArticleRepository im ArticleModel-Konstruktor, die zugehörige Liste mit $this->listing = new ListingRepository() in der Methode addListing( TArticle $article ) hinzugefügt. Sehr unschön 😕.

      lgmb

      1. Es gibt in OOP 2 Möglichkeiten Beziehungen zwischen Instanzen verschiedener Klassen herzustellen:

        1. Inherit
        2. Dependency Injection
        

        MfG

        1. moin,

          Es gibt in OOP 2 Möglichkeiten Beziehungen zwischen Instanzen verschiedener Klassen herzustellen:

          1. Inherit
          2. Dependency Injection
          

          kannst du mir wie ich auch @Rolf B bat n Anwendunsbeispiel geben? Damit kann ich mehr was anfangen 😉

          lgmb

          1. DI:

            # im Konstruktor
            $f = new ForeignClass();
            $m = new MyClass($f);
            
            # nun kann $m die Fremd-Instanz nutzen
            # Beachte jedoch: $f wurde vor der Kapselung erstellt
            # damit ist es möglich, $m von außerhalb zu verändern!!!!
            

            Zur Laufzeit, Factorymethode

            $m = new MyClass();
            
            # $m ruft eine eigene Methode
            # erst da wird die ForeignClass
            # eingebunden
            $f->challenge();
            

            In beiden Varianten ist $m->FremdInstanz das Ziel. Infolge dieser Aggregierung können Methoden der FremdInstanz an das Objekt der eigenen Klasse delegiert werden. D.h., die Methoden der fremden Klasse werden zu eigenen Methoden gemacht.

            .

            1. moin,

              schön und verständlich erklärt. Ich weis DependencyInjection bereits. Sorry wenn ich es so nicht rüber gebracht habe. Ich würde allerding so es so machen:

              new M( new F );
              

              so hat man sich schreibarbeit erspart. Sicherlich gibt es Situationen in denen dein Anwendungsbeispiel geeigneter ist. Nichts für ungut.

              lgmb

              1. moin,

                schön und verständlich erklärt. Ich weis DependencyInjection bereits. Sorry wenn ich es so nicht rüber gebracht habe. Ich würde allerding so es so machen:

                new M( new F );
                

                so hat man sich schreibarbeit erspart.

                Nicht nur das: Es hat den Vorteil, daß die F~Instanz gekapselt ist!

                Aber wirklich praktisch wirds erst mit der Factorymethode.

                .

                1. moin,

                  Aber wirklich praktisch wirds erst mit der Factorymethode.

                  oh das klingt spannend!!! Wie kann man den das FactoryPattern dort einsetzen??? Ich kenn das Pattern schon aber eben im Kontext noch nicht 😕.

                  lgmb

                  1. um im ArticleModel Grafiken und Listen zu integrieren

                    Zuerst gibst Du dem Modell eine Eigenschaft wo drinsteht, welche Grafiken und Listen das sind. Natürlich können das auch mehrere Eingenschaften sein. Je nach angeforderter Sicht greift dann die Instanz auf diese Eigenschaften zu und bedient sich deren entsprechender Methoden um die dazu benötigten Daten aus dem Repository zu holen. Um sie schließlich in das Objekt einzubauen.

                    Beispiel von mir /kloss.html Template:

                    <!-- title=Thüringer Klöße, Original Rezept -->
                    <!-- descr=Der Thüringer Kloß ist eine beliebte Sättigungsbeilage und wird nur aus Kartoffeln gemacht -->
                    <!-- parent=/beilage -->
                    <!-- bilder=/kloss/2.jpg:Werkzeug:400:300 /kloss/3.jpg:Schab:400:300 /kloss/4.jpg:Brühkartoffeln:400:300 /kloss/5.jpg:Nach_dem_Brühvorgang:400:300 /kloss/6.jpg:Garziehen:400:300 /kloss/7.jpg:Fertig_Serviert:400:300 -->
                    <!-- interface=bilder -->
                    

                    Hat eine Eigenschaft bilder und dazu das interface=bilder was die Platzhalter fürs View-Template mit Daten befüllt.

                    Schließlich werden über die TE diese Ressourcen in die Response gerendert.

                    .

                    1. moin,

                      dein sourcecode sieht sehr elegant. Ich hab eben nur im ArticleModel Bild und text in einer Methode zusammengefügt, wie oben beschrieben. Ich hab nur mit einer Überschriften-Platzhalter…

                      for( $i = 0; $i < $article->abstract; $i++ ) {
                        /* code */
                        if( $article->abstract[ $i ][ 'caption' ] === 'gallery' ) {
                          $article->abstract[ $i ][ 'content' ] = new Gallery;
                        }
                        /* code */
                      }
                      

                      …im TArticle-Objekt die Bilder oder Listen eingefügt. Meiner ansicht nach unschön. Ich hab dich verstanden und ich hab es auch so in deinem Stiel gelöst, aber meiner Ansicht nach seeehr unsauber. Wie hast du es den gelöst. Kannst du mir bitte bzgl. FactoryPattern eine weiteres nur kurzes Anwendungsbeispiel, in dem Kontext den du da hast, geben? Wenn nich ist auch nicht schlimm.

                      lgmb

                      1. Also Bilder als Eigenschaften like

                        bilder=/kloss/2.jpg:Werkzeug:400:300 /kloss/3.jpg:Schab:4 …
                        

                        werden einmal als Platzhalter im Template verwendet %bild1%, %bild2% usw. Die Seite selbst ist ja nur eine bestimmte Sicht. Eine andere Sicht wäre ein siteimagemap.xml was automatisch erstellt wird wofür nur die Konfiguration zu lesen wäre.

                        Und beachte die Eigenschaft parent=/beilage die bestimmt den Platz der Seite im übergeordneten Index.

                        Und noch ein schönes Beispiel für die Factory:

                        # Datei factory/errmsg.pm
                        
                        use strict;
                        use warnings;
                        
                        
                        *errmsg = sub{
                            my $self = shift;
                            my $errstr = shift;
                            my $url    = shift || $ENV{REQUEST_URI};
                        
                            read(DATA, my $tmpl, -s DATA);
                            $tmpl = $self->xr($tmpl, {errstr => $errstr, url => $url});
                            
                            $self->{BODY} = $tmpl.$self->{BODY};
                        };
                        
                        # Template untenstehend
                        ###########################################################################
                        __DATA__
                        <p class="error">
                            %errstr%
                        </p>
                        
                        <p>
                            <a href="%url%">Bitte die Seite neu Laden</a>
                        </p>
                        

                        Diese Methode errmsg('Fehlertext') baut eine Fehlermeldung in die Seite, Beispiel was einmal eine erstklassige Fehlerbehandlung ermöglicht und zum Anderen redundanten Code vermeidet: Jede Instanz einer Subklasse kann diese Funktion aufrufen ohne sie definieren zu müssen.

                        .

                        1. moin,

                          ich danke dir für den einblick.

                          lgmb

                          1. Eine DB Anbindung (PDO) wäre noch ein schönes Beispiel für DI+Factory. Wird eine Solche generell benötigt, etwa weil sämtliche Views eine DB Anbindung brauchen, gibst Du das PDO Objekt in den Konstruktor.

                            Ist es jedoch so, daß eine DB Anbindung nur für bestimmte Seiten und bestimmte Aktionen erforderlich ist, wird sie später erstellt. Z.B. im Rahmen einer Factory, hierzu gibt es eine Methode $pdo=$this->pdo('DBname') und wenn $pdo danach in weiteren Methoden Deiner Anwendung gebraucht wird, legst Du das PDO in eine Eigenschaft:

                            # $dbname ist eine Eigenschaft des Modells
                            $this->getProp('dbname');
                            
                            # rufe die Factory
                            $pdo = $this->pdo($dbname); 
                            
                            # SQL Statements abwickeln
                            # und danach
                            # pdo sichern für weitere Verwendung
                            $this->PDO = $pdo;
                            

                            Nutze Eigenschaften!

                            .

                            1. Tach!

                              Eine DB Anbindung (PDO) wäre noch ein schönes Beispiel für DI+Factory. Wird eine Solche generell benötigt, etwa weil sämtliche Views eine DB Anbindung brauchen, gibst Du das PDO Objekt in den Konstruktor.

                              Dann hat man eher was verkehrt gemacht. Der Controller dirigiert und stellt für die Views die Weichen. Views brauchen keinen Datenbankzugriff sondern nur die Daten. Und für deren Besorgung beauftragt der Controller das Model. Denn das Model ist für die konkrete Datenhaltung und -beschaffung zuständig.

                              dedlfix.

                              1. Was ist denn bei Dir das Modell, was der Controller und was das View in einem multidomain + multiuser + multilingual Framwework was hunderte von Webanwendungen ermöglicht?

                                1. Tach!

                                  Was ist denn bei Dir das Modell, was der Controller und was das View in einem multidomain + multiuser + multilingual Framwework was hunderte von Webanwendungen ermöglicht?

                                  Der zweite Teil der Frage ist irrelevant für das MVC-Muster als solches. Und es ist nicht meine Definition sondern wie das MVC-Muster üblicherweise beschrieben wird. Das Model ist der Teil, der die Geschäftslogik beinhaltet. Der Model-Teil ist nicht nur Entitys, die aus Eigenschaften bestehen, wie beispielsweise eine Person und deren Daten, sondern dahinter verbirgt sich auch die Verarbeitung und Beschaffung der Daten.

                                  Die View ist für die Präsentation der Daten zuständig. Wo die Daten dafür herkommen, muss der View egal sein, wenn man flexibel bleiben und keine unnötigen Abhängigkeiten quer durch die Anwendung ziehen möchte.

                                  Der Controller ist jedenfalls dann derjenige Teil, der für eine konkrete Anforderung das Model beauftragt, die Daten für die View zu besorgen.

                                  In kleinen Anwendungen besteht das Model aus Datenbankzugriff und ein paar Entitys, die die Datenobjekte des Anwendungsfalles darstellen. In größeren nimmt man da gern noch weitere strukturierende Dinge hinzu, wie ORMs, Repositorys und Domain Services (Domain = Anwendungsbereich)

                                  dedlfix.

                                  1. Was ist denn bei Dir das Modell, was der Controller und was das View in einem multidomain + multiuser + multilingual Framwework was hunderte von Webanwendungen ermöglicht?

                                    Der zweite Teil der Frage ist irrelevant für das MVC-Muster als solches.

                                    Doch das ist er ganz entscheidend!

                                    1. Tach!

                                      Was ist denn bei Dir das Modell, was der Controller und was das View in einem multidomain + multiuser + multilingual Framwework was hunderte von Webanwendungen ermöglicht?

                                      Der zweite Teil der Frage ist irrelevant für das MVC-Muster als solches.

                                      Doch das ist er ganz entscheidend!

                                      Das sehe ich nicht so, denn für mich haben diese Stichwörter keinen Einfluss auf die grundlegende MVC-Architektur und deren Zuständigkeiten.

                                      Dann kommt es noch drauf an, was du unter den Begriffen vestehst. Mehrsprachigkeit ist ziemlich klar, da ist grob gesagt eine Frage des passenden Templates. Sind sprachspezifisch unterschiedliche Daten zu holen, ist das eine Aufgabe für den Controller, die passenden Daten aus dem Model abzufragen. Gegebenenfalls kommen allgemeine Services hinzu für Übersetzungsarbeiten, aber das sind keine Tätigkeiten, die der View-Teil steuert.

                                      Wenn du unter "multidomain" DNS-Einträge meinst, dann ist das ein Thema für den Router (außerhalb des MVC-Musters), die Daten des Requests zu analysieren und ein entsprechendes Ziel anzusteuern.

                                      Bei "multiuser" wird es schwammig. Ist da Mandantenfähigkeit gemeint oder ein mehr oder weniger einfaches Konzept der Nutzer- und Rechteverwaltung? Aber auch das sind keine Themen der View, sondern des Model-Teils und den von ihm angesprochenen Services, gegebenenfalls unter steuernder Wirkung des Controllers.

                                      dedlfix.

                                      1. Grundsätzlich sehe ich den MVC auch so. Aber nicht als Dogma. Und auch nicht als Entwurfsmuster. Bei einem multiuser (mandantenfähigen), multidomain und multilingualen Framework sind andere Fragen vordergründig, das ist nicht eine Frage des Entwurfsmusters sondern eine Frage der Organisation und einer guten Idee.

                                        Treffender für Webanwendungen ist das Transition state Model und ohnehin brauchen Webanwendungen eine Darstellungsschicht (View) für die gewöhnlich eine Templating Engine die Schnittstelle darstellt.

                                        So kommt für meine Begriffe ein Controller erst ins Spiel wenn es Zustandsübergänge gibt z.B. infolge von Benutzereingaben.

                                        Der Begriff Model ist in dieser Hinsicht bedeutungslos, was soll denn modelliert werden? Daten werden strukturiert und nicht modelliert! Genausowenig wird eine Geschäftslogik modelliert sondern auf Kontrollstrukturen abgebildet.

                                        Und für die Datenhaltung (Persistierung) gibt es Layer.

                                        1. Tach!

                                          Grundsätzlich sehe ich den MVC auch so. Aber nicht als Dogma. Und auch nicht als Entwurfsmuster.

                                          Das kannst du gern so handhaben. Dagegen spricht ja auch nichts. MVC ist nur eines von vielen Mustern. Aber was nicht die beste Vorgehensweise ist, wenn ausdrücklich nach den Gegebenheiten beim MVC-Paradigma gefragt wurde, mit Gegebenheiten anderswo zu antworten und vor allem das nicht klar herauszustellen, dass man sich nicht auf das eigentliche Thema bezieht. Es ist dabei nicht das Problem, Alternativen aufzuzeigen, sondern sie nicht klar solche darzustellen.

                                          Der Begriff Model ist in dieser Hinsicht bedeutungslos, was soll denn modelliert werden? Daten werden strukturiert und nicht modelliert! Genausowenig wird eine Geschäftslogik modelliert sondern auf Kontrollstrukturen abgebildet.

                                          Model steht hier nicht für die Abbildung von Gegebenheiten des Anwendungsfalles auf eine Datenstruktur, also eine Modellierung von Teilen der Wirklichkeit (und ja, hier wird modelliert, ein Modell erzeugt), sondern für alles was mit Daten und deren Verarbeitung zu tun hat, also für die gesamte Geschäftslogik einer Anwendung. Der Begriff Model ist da vielleicht nicht ganz treffend im eigentlichen Wortsinne gewählt, aber bei MVC steht Model eben für diese Gesamtheit.

                                          Und für die Datenhaltung (Persistierung) gibt es Layer.

                                          Nee, dafür gibt es Datenbanken, Dateien und dergleichen. Layer sind Strukturierungen eines Systems, und die Datenhaltung ist nur ein Layer unter anderen.

                                          MVC beschreibt nur eine grobe Einteilung. Dass bestimmte Teile davon weiter untergliedert werden, und dass für eine vollständige Anwendung noch Teile abseits des MVC-Pattern benötigt werden, steht dem nicht im Wege. Selbstverständlich hat eine gut strukturierte Anwendung außer dem Dreieck M-V-C noch Dinge, die in Schichten angeordnet werden können. Und auch ja, MVC ist vielleicht nicht das allerbeste für jede Situation bei Webanwendungen, aber es ist nun mal eine der bekanntestes Herangehensweisen.

                                          dedlfix.

                                          1. Datenaustausch ist ist nicht MVC spezifisch! Und im Übrigen ging es hier um OOP, nämlich um den Datenaustausch zwischen Klassen (Inherit und Dependency Injection)!

                                            1. Tach!

                                              Datenaustausch ist ist nicht MVC spezifisch!

                                              Hab ich was anderes behauptet?

                                              Und im Übrigen ging es hier um OOP, nämlich um den Datenaustausch zwischen Klassen (Inherit und Dependency Injection)!

                                              OOP war eher nebensächlich, das eigentliche Thema war grundlegender Natur, wie man was und auf welche Weise zusammenbaut.

                                              dedlfix.

      2. Hallo MB,

        wie PL schon schreibt - grundsätzlich gibt's bei OO die Vererbung und Referenzen auf andere Objekte. Vererbung scheint mir hier nicht zur Lösung beizutragen.

        Um einem Objekt eine Referenz auf ein anderes Objekt zu verschaffen, gibt's verschiedene Wege. Der schlechteste ist, wenn sich ein Objekt die Referenz selbst holt, denn damit erzeugt man eine fest verdrahtete Beziehung zwischen den Objekten. Das ist nicht im Sinne der Informatik. Entkoppelung ist das Ziel, das schafft Testbarkeit und Austauschbarkeit.

        Deswegen bekommt ein Objekt seine Referenzen auf andere Objekte sinnvollerweise von außen eingesetzt, das nennt man Dependency Injection. Es gibt Bibliotheken, die sowas per Deklaration automatisch tun, aber es geht auch manuell.

        Dass ein Model eine Referenz auf ein Repository hält, ist allerdings merkwürdig. Eher sollte das Repository eine get oder suche Funktion haben, die das ArticleModel liefert. Analog muss das ListingRepository ein TListing Objekt liefern. Und der Controller steckt dann beides zusammen. Man kann Abhängigkeiten über den Konstruktur injizieren, oder durch Zuweisungen an öffentliche Properties.

        Wenn Du in mehreren Controllern ArticleModel Objekte aufbauen musst, kann auch eine Klasse ArticleModelBuilder eine Lösung sein. Sie kennt die Repositories und weiß wie man den Objektbaum des ArticleModel zusammensetzt.

        Wenn aber ArticleModel und TListing immer zusammen gehören, wenn ein TListing ohne ein ArticleModel gar nichts bedeutet, dann gehört das Ermitteln von TListing mit ins ArticleRepository. Die beiden bilden dann nämlich eine Business Domain, und ein Repository sollte sich mit einer BusinessDomain befassen, nicht mit einer Table.

        Viele Wege führen zum Ziel. Jeder hat seine Vor- und Nachteile.

        Rolf

        --
        sumpsi - posui - clusi
        1. @Rolf B

          Um einem Objekt eine Referenz auf ein anderes Objekt zu verschaffen, gibt's verschiedene Wege. Der schlechteste ist, wenn sich ein Objekt die Referenz selbst holt, denn damit erzeugt man eine fest verdrahtete Beziehung zwischen den Objekten.

          Die hast Du auch wenn wenn Du die fremde Instanz vor der eigenen Objektersteliung einbaust.

          Der Unterschied ist praktischer Natur: Wenn sich eine Instanz zur Laufzeit einer fremden Instanz bedient, ermöglicht das den Aufbau einer Factory. Und eine Factory heißt, daß man seine Instanz praktische um beliebig viele Methoden erweitern kann deren Code nur dann kompiliert wenn er gebraucht wird.

          Und daraus ergeben sich ne ganze Reihe an weiteren Vorteilen. Unter Anderem ist das eine effiziente Methode, redundanten Code zu vermeiden. Wobei die Factory hierzu nicht unbedingt fremde Klassen einbinden muss.

          .

          1. Hallo pl,

            deren Code nur dann kompiliert wenn er gebraucht wird

            Die Nummer hatten wir schon mal. Das ist sprachspezifisch.

            Das dazu passende, für statische Sprachen konzipierte Pattern der Gang of Four ist der Decorator, aber Dependency Injection ist viel weiter gehend.

            Rolf

            --
            sumpsi - posui - clusi
            1. @Rolf B

              deren Code nur dann kompiliert wenn er gebraucht wird

              Die Nummer hatten wir schon mal. Das ist sprachspezifisch.

              Perl und PHP haben das gmeinsam.

              Das dazu passende, für statische Sprachen konzipierte Pattern der Gang of Four ist der Decorator, aber Dependency Injection ist viel weiter gehend.

              Mir persönlich sind Begriffe wie Aggregation und Delegation lieber. Aber nicht nur aus praktischen Gründen sondern weil sie ganz einfach näher dran an meiner Muttersprache sind.

              .

        2. moin,

          wie PL schon schreibt - grundsätzlich gibt's bei OO die Vererbung und Referenzen auf andere Objekte. Vererbung scheint mir hier nicht zur Lösung beizutragen.

          Ok warum? wen keine Vererbung, wie denn dann wenn nicht so? kannst du mir n konkretes Anwendungs-Beispiel geben?

          Um einem Objekt eine Referenz auf ein anderes Objekt zu verschaffen, gibt's verschiedene Wege. Der schlechteste ist, wenn sich ein Objekt die Referenz selbst holt, denn damit erzeugt man eine fest verdrahtete Beziehung zwischen den Objekten. Das ist nicht im Sinne der Informatik. Entkoppelung ist das Ziel, das schafft Testbarkeit und Austauschbarkeit.

          Entkoppelung? Hier schwer zu realisieren finde ich :/. Auch hier ein kleines Beispiel?

          Dass ein Model eine Referenz auf ein Repository hält, ist allerdings merkwürdig. Eher sollte das Repository eine get oder suche Funktion haben, [...]

          hat es.

          [...] die das ArticleModel liefert.

          ein TArticle-Objekt ja

          Analog muss das ListingRepository ein TListing Objekt liefern.

          tut es.

          Und der Controller steckt dann beides zusammen.

          Ich hab das im Model gemacht.

          Man kann Abhängigkeiten über den Konstruktur injizieren, oder durch Zuweisungen an öffentliche Properties.

          Kannst du mir wieder n kleines Anwendungsbeispiel geben, damit ich weis wo du gedanklich bist?

          Wenn Du in mehreren Controllern ArticleModel Objekte aufbauen musst, kann auch eine Klasse ArticleModelBuilder eine Lösung sein. Sie kennt die Repositories und weiß wie man den Objektbaum des ArticleModel zusammensetzt.

          Ja ich hab ein paar: ProjectControler, ImpressumControler, AboutController, PagesController. ProjectControler Index gib ne short view der Artikel, aber noch kein wirklichen Artikel in voller länge. Wie hilft da n Builder der GoF?

          Wenn aber ArticleModel und TListing immer zusammen gehören, wenn ein TListing ohne ein ArticleModel gar nichts bedeutet, dann gehört das Ermitteln von TListing mit ins ArticleRepository.

          tun sie nicht.

          Die beiden bilden dann nämlich eine Business Domain, und ein Repository sollte sich mit einer BusinessDomain befassen, nicht mit einer Table.

          ok was ist eine BuisnessDomain. Wahrscheinlich kenne ich das oder auch weniger. Kannst du mir wieder ein kurzes Anwendungbeispiel geben?

          Sorry wenn ich dich mit der Forderung von Anwendungsbeispielen zu kleister 😉.

          lgmb

        3. moin,

          wie PL schon schreibt - grundsätzlich gibt's bei OO die Vererbung und Referenzen auf andere Objekte. Vererbung scheint mir hier nicht zur Lösung beizutragen.

          Bitte entschuldige ich war im stress. jetzt bin ich gechillter. Ich glaube du meinst sowas:

          class Foo {
            public function __construct( Bar $bar ) {
              $this->bar = $bar;
            }
          }
          

          die Vererbung hat schon seinen Zweck wenn ich das schreibe. Wenn ich reusable Code habe lohnt sich meiner Ansicht nach Inheritance.

          class FooParent {
            
            protected $bar;
          
            public function __construct() {
              $this->bar = new Bar;
            }
          
          }
          
          class TokChild extends FooParent {
            
            public function __construct() {
              parent::__construct();
            }
          }
          
          class QuxChild extends FooParent {
            
            public function __construct() {
              parent::__construct();
            }
          }
          

          so hat man mehr freiraum finde ich aber belehre mich eines besseren 😀.

          lgmb

          1. Hallo MB,

            das ist jetzt ziemlich viel geworden, und ich kann kaum auf jeden Punkt einzeln eingehen. Du darfst jedenfalls gern anderer Meinung sein wie ich.

            Vererbung scheint mir hier nicht zur Lösung beizutragen. Ok warum? wen keine Vererbung, wie denn dann wenn nicht so?

            Es ging mir hier um die Frage, wie man ArtikelModel und TListing zusammenbringt. Das heißt nicht, dass Du generell die Finger von Vererbung lassen sollst.

            Entkoppelung? Hier schwer zu realisieren…

            Entkoppelung ist immer schwerer zu realisieren als Objekte, die sich ihre Bezugsobjekte eben mal selbst beschaffen. Aber beschäftige Dich mal mit der Idee des Unit Testing, und Du wirst es hassen, dass in ArtikelModel ein new Irgendwas() steht, wenn Du eigentlich nur das Model testen willst und das Irgendwas-Objekt viel lieber durch einen vereinfachten Test-Stub[1] ersetzen möchtest. Insbesondere Repositories, die die Daten beschaffen, werden bei Unit Tests gerne durch Testexemplare substituiert, um definierte Objekte ohne DB-Abhängigkeit zu haben.

            Natürlich musst Du immer schauen, was für Dich passt. Aber in einer Anwendung von mir habe ich eine statische Klasse Context gemacht, die eine statische Eigenschaft $Controllers hat. Darin liegt die Controller-Factory, und einen Controller bekommst Du z.B. mit Context::$Controllers->getArticleController(). Die Factory übergibt automatisch eine Referenz auf die Repository-Factory - und ein Controller, der das nicht annimmt, geht kaputt weil der abstrakte Controller das Ding im Konstruktor haben will.

            class Controller {
               protected $Repositories;
               protected function __construct(RepositoryFactory $rep) {
                  $this->Repositories = $rep;
               }
            }
            class ArticleController extends Controller {
              public function __construct($repFac) {
                parent::__construct($repFac);
                $this->model = $this->Repositories->getArticleRepository()->newArticleModel();
              }
            }
            class ArticleModel extends Model {
              public function __constructor(ArticleRepository rep) {
                $this->repository = rep;
              }
            }
            

            ABER: Das ist jetzt eine ganz andere Komplexitätsstufe, und wenn Du eh schon am fluchen bist, hilft Dir das vermutlich nicht weiter. Die wichtigste Waffe im Kampf gegen das "Ich kapier's nicht mehr" ist strukturieren. Divide et impera!

            Ein Builder war nur eine Idee falls das Aufbauen von Models umfangreicher ist. Dann möchte man das gerne irgendwohin auslagern.

            Mit Business Domain meine ich eine Gruppe von Tables, die zusammengehören. Eine davon ist dann typischerweise die Haupt-Table, die anderen enthalten abhängige Daten, und werden immer zusammen mit der Haupt-Table gelesen, bzw. über ein Objekt das aus der Haupt-Table erzeugt wurde. Man würde dann kein Repository für die abhängigen Tables erzeugen.

            Wir sind hier immer noch sehr abstrakt unterwegs, ich kann Dir darum keine konkreten Vorschläge für eine Implementierung machen. Angesichts des Projektumfangs könnte das auch zu weit führen.

            Rolf

            --
            sumpsi - posui - clusi

            1. Ob Stub oder Mock oder Fake oder sonstwas - die Unittest-Päpste definieren sich da gerne den Wolf. Ich benutze in C# für sowas NSubstitute und die sagen dazu nur: We could ask for a stub, mock, fake, spy, test double etc., but why bother when we just want to substitute (...) ↩︎

            1. moin,

              erstmal herzlichen für die mühe. fast exakt so habe ich es auch gemacht aber eben nicht mit DI weil mir das nicht zielführed ist eine Instanz ständig rumzureichen bis sie dann mal entsteht. Ich vermute du meinst sowas.

              abstract class Controler {
                
                protected $fu = null;
                
                protected function __construct( Fu $fu ) {
                  $this->fu = $fu;
                }
                
                public function getFu() : Fu {
                  return $this->fu;
                }
              }
              
              class FooControler extends Controler {
                public function __construct( Fu $fu ) {
                  parent::__construct( $fu );
                }
              }
              
              $foo = new FooControl( new Fu );
              $foo->getFu();
              

              ginge das auch…

              abstract class Controler {
                
                protected $_model = null;
              
                public function getModel : IModel {
                  return $this->_model;
                }
              }
              
              class FooControler extends Controler {
                
                public function __construct() {
                  $this->_model = new BarModel
                }
              }
              
              abstract class Model {
                
                protected $_repository = null;
              
                public function getRepository() : IRepository {
                  return $this->_repository;
                }
              }
              
              class BarModel extends Model {
                
                public function __construct() {
                  $this->_repository = new BarRepository
                }
              }
              
              
              abstract class Repository {
                
                protected $_repository = null;
                
                public function __construct() {
                  $this->_database = new Database;
                }
                
                public function getDatabase() : array {
                  return $this->_database;
                }
              }
              
              class BarRepository extends Repository {}
              

              da hat man schon vorher ziehmlich viel vordefiniert und brauch sich weniger sorgen zu machen finde ich. Jedoch kriege ich eben das mit der Eingangsfrage nicht hin. Aufjedenfall habe ich erstmal von euch beiden stoff der mir bei meiner Eingangsfrage helfen wird 😉.

              lgmb

              1. Hallo MB,

                das Thema DI war ja auch nur ein Randthema. Aus meiner Sicht hast Du die Welt auf den Kopf gestellt und erzeugst alle Objekte am falschen Ort - aber das ist eben meine Sicht und deine ist anders.

                Das eigentliche Problem, das Du hast, ist mir aber immer noch nicht klar. Es ist immer noch abstrakt. Zentrales Element ist immer der Controller (mit 2 L übrigens :) ). Der kennt das Model, der aktiviert einen View. Wenn es für einen Controller, ein Model, einen View zu komplex wird, ist es an der Zeit aufzuteilen. Subcontroller, strukturierte Models, Teil-Views. Das habe ich schon gesagt und ohne weitere Kenntnis deiner Aufgabenstellung kann ich wohl auch nicht mehr tun.

                Rolf

                --
                sumpsi - posui - clusi
                1. moin,

                  Ach mist! Wie peinlich. Ja, ich schrieb einen stuss, ist mir klar geworden jetzt wo du es sagst. Anders rum. Dankeschön für die subtile zurechtweisung.

                  lgmb

                2. Tach!

                  Wenn es für einen Controller, ein Model, einen View zu komplex wird, ist es an der Zeit aufzuteilen. Subcontroller, strukturierte Models, Teil-Views.

                  Und auch Dinge außerhalb des MVC-Patterns. Services bieten sich an, konkrete Aufgaben zu erledigen, die sich aus dem Anwendungsfall ergeben, die zu viel sind für einen Controller oder die von mehreren Stellen aus angesprochen werden müssen. Die arbeiten dann nach oben hin mit wem auch immer, der die Dienste braucht zusammen und nach unten hin mit dem Model oder anderen Datenquellen.

                  Ich verweise an der Stelle mal auf ein Application Framework namens "ASP.NET Boilerplate". Das ist zwar in C# geschrieben und im Hinblick auf die Belange und Notwendigkeiten im "ASP.NET MVC"-Ökosystem. Doch für das Thema hier sind eher Teile von dessen Dokumentation interessant. Im Speziellen meine ich da die Seite zur NLayer Architecture.

                  Dazu ein großes Aber: In dem Framework sind zwar jede Menge Dinge drin, die man recht häufig in vielen Projekten finden kann. Aber nicht alles braucht man überall. Die dort gezeigte Komplexität in voller Schönheit lohnt sich erst ab bestimmten Projektgrößen. Bei kleineren kann man durchaus Abkürzungen nehmen. So eine Architektur ist ja kein Gesetz sondern nur ein Vorschlag und man darf die Dinge auch anders sehen und implementieren.

                  dedlfix.

  2. moin,

    wie kriegt man im MVC-Paradigma Bild und Text unter?

    Mit einem zweckmäßigen Content Management! Und ja, es gibt Content Types, nutze sie!

    MfG