Ergebnis 1 bis 12 von 12

Thema: Contao Module in Git Repository für mehrere Projekte

  1. #1
    Contao-Nutzer
    Registriert seit
    11.09.2016.
    Beiträge
    79

    Standard Contao Module in Git Repository für mehrere Projekte

    Hallo zusammen,
    ich habe eine grundlegende Frage zum Workflow mit Contao und Git.

    Gegeben sei folgende Ausgangssituation: Ein Contao Modul wurde entwickelt und steht mittels Git in einem Repository unter Versionsverwaltung. Dieses Modul ist z.B. dafür da um Datenbankeinträge auszulesen und auf einem Template auszugeben.

    Dieses Modul bzw. dieses Repositiry ist sozusagen der „core“ eines Projektes.
    Nun kommt hinzu, dass dieses Projekt nicht einfach so auf einen Webserver geladen werden soll, sondern in verschiedenen, teilweise vielleicht auch leicht modifizierten, Versionen für verschiedene Projekte verwendet werden soll.

    Beispiel: Der „core“ wird in Projekt A mit roter Hintergrundfarbe und lustigen Texten aus dem languages Ordner ausgeliefert und in Projekt B mit grauem Hintergrund und ernsthafteren Texten (stark vereinfachtes und zugegeben lächerliches Beispiel, soll heißen, dass z.B. die Assets und Languages von Projekt zu Projekt variieren).

    Es soll verdeutlicht werden, dass der “core“ für verschiedene Systeme verwendet werden soll, die a) individuell angepasst werden sollen und b) Arbeiten und Verbesserungen an besagtem „core“ allen davon abgezweigten Projekten zur Verfügung stehen soll (Updates aus dem Core sollen sich die Projekt-Clients pullen können).

    Die Frage aller Fragen ist nun, in wie fern sich dieses Vorhaben mit der Contaowelt vereinbaren lässt.
    Natürlich könnte man über Git-Submodule das core-Repo einbinden, ich sehe dann Aber Probleme mit der Modulstruktur in Contao. Man müsste dann vermutlich zwei Module miteinander verheiraten oder ähnlich.

    Hat jemand ähnliche Probleme oder Situationen zu lösen gehabt oder eine Idee wo es Infomaterial zu einem „best practise“ solcher Fälle gibt?

    Vielen Dank und schöne Grüße
    *igi*

  2. #2
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.114
    Partner-ID
    10107

    Standard

    Spontan sehe ich folgende Möglichkeiten:

    1. Du lässt die allgmeine Version des "Core" im Repository und die Änderungen für die jeweiligen Projekte setzt du in einer anderen Extension um.
    2. Du arbeitest einfach mit verschiedenen Branches und verwendest für jedes Projekt einen eigenen Branch.

  3. #3
    Contao-Fan Avatar von PaddySD
    Registriert seit
    26.10.2016.
    Ort
    Andechs
    Beiträge
    656

    Standard

    Ich halte hier einen ganz normalen "Modul"-Workflow für das Beste.

    Du hast ein Core-Modul, indem alle wichtigen Funktionen enthalten sind. Alles was an Änderungen kommt, packst Du in ein Zusatzmodul. Ersichtlich funktioniert das dann so, dass Du halt in den Zusatzmodulen den "core" als required setzt.

    Die Module können ja jederzeit ineinander greifen, und auch die Daten gegenseitig manipulieren. Das geht mittlerweilen sehr gut, u.a. weil man dank der Änderungen in der template-Engine auch ganz einfach die Templates verändern kann.

    Verheiraten ist gar nicht nötig, wenn Du Dich an die entsprechenden Klassensturkturen hälst und eben vererbst oder überschreibst.

    Das allerbeste Beispiel hast Du in Contao selbst. Der Core ist ein Modul, mit allerlei Submodulen, obwohl er selbst als Modul läuft.

  4. #4
    Contao-Nutzer
    Registriert seit
    11.09.2016.
    Beiträge
    79

    Standard

    Hey ho,

    @Spooky: Die Variante zwei hatte ich auch schon im Hinterkopf. Jedoch würde dies ja die eigentliche Logik bzw. den Grundgedanken des Git-Prinzips über den Haufen werfen. Diese Branches würden ja niemals wieder in den Master-Branch zurückgemerged werden. Wenn ich Änderungen im core vornehme müsste ich diese dann vermutlich in die abgezweigten Projektbranches mittels rebase überführen.

    Die erste Variante mit separaten Modulen ist glaube ich der sauberere Ansatz.
    Hier finde ich auch den Vorschlag von dir, PaddySD, sehr gut.
    Der core stellt ein eigenes Modul dar, welches jedes Unterprojekt haben muss. Zusätzlich hat jedes Unterprojekt sein eigenes „custom Modul“ mit den jeweiligen individuellen Anpassungen.

    In der Theorie finde ich das prima, weiß aber noch nicht genau wie dies in der Praxis am besten umzusetzen ist.
    Könnte ich z.B. sagen: verwende Grundsätzlich alle Dateien aus dem core-Modul, es sei denn das custom-Modul hat diese Dateien „überschrieben“, dann nehme bitte diese Version?

  5. #5
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.114
    Partner-ID
    10107

    Standard

    Zitat Zitat von *igi* Beitrag anzeigen
    Diese Branches würden ja niemals wieder in den Master-Branch zurückgemerged werden. Wenn ich Änderungen im core vornehme müsste ich diese dann vermutlich in die abgezweigten Projektbranches mittels rebase überführen.
    Ja, so habe ich mir das auch gedacht . Allgemeine Änderungen -> master -> merge into branches (when required). Projektänderungen -> branch.


    Zitat Zitat von *igi* Beitrag anzeigen
    Die erste Variante mit separaten Modulen ist glaube ich der sauberere Ansatz.
    Hier finde ich auch den Vorschlag von dir, PaddySD, sehr gut.
    Der core stellt ein eigenes Modul dar, welches jedes Unterprojekt haben muss. Zusätzlich hat jedes Unterprojekt sein eigenes „custom Modul“ mit den jeweiligen individuellen Anpassungen.

    In der Theorie finde ich das prima, weiß aber noch nicht genau wie dies in der Praxis am besten umzusetzen ist.
    Könnte ich z.B. sagen: verwende Grundsätzlich alle Dateien aus dem core-Modul, es sei denn das custom-Modul hat diese Dateien „überschrieben“, dann nehme bitte diese Version?
    Ein einfaches Beispiel:

    Angenommen du hast im "core_modul" eine Sprachdatei languages/de/default.php mit gewissen Übersetzungen. Du benötigst in einem der Projekt-Module aber eine andere Übersetzung, zB für
    PHP-Code:
    $GLOBALS['TL_LANG']['core_modul']['foo'
    . Im "projekt_modul" hast du dann also eine config/autoload.ini mit dem Inhalt
    Code:
    requires[] = "core_modul"
    und dann ebenfalls eine Datei namens languages/de/default.php wo du dann
    PHP-Code:
    $GLOBALS['TL_LANG']['core_modul']['foo'
    überschreibst.

    Ähnliches kannst du mit DCA Konfigurationen machen und du kannst (zumindest in Contao 3) auch Klassen aus deinem "core_modul" mit anderen ersetzen, über die config/autoload.php.

  6. #6
    Contao-Nutzer
    Registriert seit
    11.09.2016.
    Beiträge
    79

    Standard

    Ah verstehe, das klingt schon mal sehr interessant. Das werde ich ausprobieren!
    Zu der autoload.php... bis jetzt habe ich den bequemen Weg gewählt, diese im Contao BE über den Autoload-Creator erstellen zu lassen.
    Sehe ich es richtig, dass diese Option dann weg fällt, wenn ich hier manuell Einträge editiere? Oder meintest du die autoload.ini?

  7. #7
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.114
    Partner-ID
    10107

    Standard

    Die autoload.php wird vom Autoload Creator erstellt. Die autoload.ini definiert was der Autoload Creator machen soll und was nicht und dort werden auch Abhängigkeiten zu anderen Contao Extensions definiert.

  8. #8
    Contao-Fan Avatar von PaddySD
    Registriert seit
    26.10.2016.
    Ort
    Andechs
    Beiträge
    656

    Standard

    Du kannst das ganze sogar noch weiter treiben. Zumindest in der 3.x ist das alles sehr gut machbar. 4.x kann ich noch nicht beurteilen, hab gerade mal eine Installation laufen...

    Zurück zum Thema...

    Stell es Dir mal anders vor, jedes Modul ist in gewissem Sinne ein Submodul des Conta-core. Und wenn Du ein Submodul als eigenständige Erweiterung, anstelle eines "Sub" versuchst zu sehen, geht's gleich leichter...

    Ein kleines Beispiel:
    Wir haben ein Modul, dass der Verwaltung von Kunden dient (moduleClients) und ein zweites, für Spenden (moduleDonations).

    In der autoload.ini von moduleDonations haben wir das hier:
    PHP-Code:
    ;;
    ; List 
    modules which are required to be loaded beforehand
    ;;
    requires[] = "core"
    requires[] = "*moduleClients" 
    Damit wird moduleClients vor moduleDonations geladen, wenn es vorhanden ist (*). Für Deine autoload.ini z.B.:
    PHP-Code:
    ;;
    ; List 
    modules which are required to be loaded beforehand
    ;;
    requires[] = "core"
    requires[] = "meinCoreModul"
    requires[] = "meinSubmodulFuerBlaueHintergruende" 
    Dann müssen beide (Sub-)Module da sein, bevor Deine Erweiterung geladen wird.

    Jetzt kannst Du in der config noch auf das vorhandensein prüfen und erstellst z.B. entsprechend die Einträge im Menü links:
    PHP-Code:
    if (!is_array($GLOBALS['BE_MOD']['moduleDonations']))
    {
        if (!isset(
    $GLOBALS['BE_MOD']['moduleClients']))
        {
            
    array_insert($GLOBALS['BE_MOD'], 3, array('moduleDonations' => array()));
        }
    }
    // Oberhalb schauen wir, ob moduleClients da ist, nein, dann brauchen wir einen eigenen Menü-Oberpunkt!
    if (isset($GLOBALS['BE_MOD']['moduleClients']))
    {
        
    array_insert($GLOBALS['BE_MOD']['moduleClients'], 1, array(
        
    'donations' => array
        (
            
    'tables'      => array('tl_donations'),
            
    'icon'        => 'system/modules/moduleDonations/assets/icon.png'
        
    ),
        
    'donors' => array
        (
            
    'tables'      => array('tl_donors'),
            
    'icon'        => 'system/modules/moduleDonations/assets/icon.png'
        
    ),
    ));
    }
    else
    {
        
    array_insert($GLOBALS['BE_MOD']['moduleDonations'], 0, array(
        
    'donations' => array
        (
            
    'tables'      => array('tl_donations'),
            
    'icon'        => 'system/modules/moduleDonations/assets/icon.png'
        
    ),
        
    'donors' => array
        (
            
    'tables'      => array('tl_donors'),
            
    'icon'        => 'system/modules/moduleDonations/assets/icon.png'
        
    ),
    ));
    }
    // Selbiges hier, gibt es moduleClients, hängen wir unsere Menüpunkte für moduleDonations drunter, sonst alleine unter dem neuen Menü-Oberpunkt 
    Bei den Klassen extendest Du einfach weiter:
    PHP-Code:
    class donations extends clients{} 
    Und schon hast Du alles was Du brauchst zur Verfügung. Methoden überschreiben usw.

    Du kannst mit etwas Aufwand sogar die Core-Klassen von Contao selbst überschreiben, wenn nötig, indem Du Deine gleichlautende Klasse einfach nachher lädst (laden lässt). Klappt wunderbar.

    Ich glaube ehrlich gesagt, dass ist der einzig wirklich gangbare Weg. Ansonsten verliert man sehr, sehr schnell die Übersicht. Ich kapsele mittlerweilen alles, was sich irgendwie aufteilen lässt einzeln ab. Hat zudem den Vorteil, gerade wenn Du mit gitlab oder github arbeitest, dass Du ja Deine Sachen auch entsprechend schnell in andere Projekte übernehmen kannst. Wr weiss schon, wann Du Deinen blauen Hintergrund wieder brauchst.

  9. #9
    Contao-Nutzer
    Registriert seit
    11.09.2016.
    Beiträge
    79

    Standard

    Weltklasse meine Herren,

    immer wenn ich denke, dass ich Contao langsam mal an die Grenzen seiner Möglichkeiten gebracht habe, kommen hier Antworten, die das genaue Gegenteil beweisen
    Ich habe das von euch beschriebene mal in einer kleinen Demoanwendung nachgestellt bzw. ausprobiert.

    Modul "demo_core" enthält die Grundfunktionen der Anwendung und "demo_sub" ist ein fast nacktes Modul, das lediglich eine modifizierte Version des Templates und einen config Eintrag enthält:

    Code:
    requires[] = "demo_core"
    Wenn ich jetzt das Core-Modul einbinde, wird durch das Template auch tatsächlich nur die modifizierte Version des demo_sub Moduls ausgegeben.

    Das einzige was ich noch nicht ganz verstanden habe, ist wie die Ableitung von Klassen in diesem Szenario funktioniert.

    demo_core hat eine einfache Klasse "DemoClass.php". Diese enthält zwei Funktionen:
    Code:
    public function getDemo()
    {
    	return "Demo A";
    }
    
    public function getDemo2()
    {
    	return "Demo 2";
    }
    Hier möchte ich nun getDemo überschreiben, so dass diese einen anderen String zurück gibt.
    Wenn ich diese Klasse nun in dem demo_sub Modul ebenfalls erstelle und den gleichen Namen vergebe, meckert er jedoch

    Code:
    Cannot declare class SubDemo\DemoClass because the name is already in use...
    Code:
    namespace SubDemo;
    
    use Demo\DemoClass;
    
    
    class DemoClass extends DemoClass
    {
    
        public function getDemo()
        {
            return "Demo B";
        }
    }
    Wie kann ich die Klasse nun so überschreiben, dass ich lediglich die getDemo ersetze / erweitere ohne die gesamte Klasse zu kopieren?
    Ich habe das Modul "demo_core" im Namespace "Demo" und das Modul "demo_sub" im Namespace "SubDemo" registriert.

    Vielen Dank schon mal und viele Grüße
    *igi*

  10. #10
    Community-Moderator
    Wandelndes Contao-Lexikon
    Avatar von Spooky
    Registriert seit
    12.04.2012.
    Ort
    Scotland
    Beiträge
    34.114
    Partner-ID
    10107

    Standard

    Sieh dir als Beispiel die Extension codefog/contao-news_categories an.

    Diese Extension liefert zB. ihr eigenes NewsModel, welches vom Contao\NewsModel ableitet: https://github.com/codefog/contao-ne...el.php#L16-L21

    In der autoload.php wird dieses Model ganz normal geladen: https://github.com/codefog/contao-ne...toload.php#L35

    Nun ist es aber so, dass in Contao 3 alle Klassen in den Root Namespace gemapped werden. Das heißt, statt \Contao\NewsModel kann das NewsModel auch mit \NewsModel angesprochen werden - und Contao spricht auch alle Klassen so an. Wenn nun aber ein zweites NewsModel registriert wird (egal in welchem Namespace), dann ersetzt das zweite NewsModel das Root Mapping des ersten. Das heißt \NewsModel ist jetzt nicht mehr \Contao\NewsModel sondenr \NewsCategories\NewsModel.

    Ähnlich kannst du auch bei dir vorgehen. Wenn du in demo_sub nun ganz normal deine \SubDemo\DemoClass über die autoload.php lädst, is nun über \DemoClass die \SubDemo\DemoClass verfügbar, statt die \Demo\DemoClass. Damit das funktioniert brauchst du evt. auch noch
    PHP-Code:
    ClassLoader::addNamespace('SubDemo'); 
    in der autoload.php, aber da bin ich mir nicht sicher.

    Hier ist übrigens ein Fehler, glaube ich:
    Zitat Zitat von *igi* Beitrag anzeigen
    Code:
    namespace SubDemo;
    
    use Demo\DemoClass;
    
    
    class DemoClass extends DemoClass
    {
    
        public function getDemo()
        {
            return "Demo B";
        }
    }
    Das muss wohl
    Code:
    namespace SubDemo;
    
    use \Demo\DemoClass;
    
    
    class DemoClass extends DemoClass
    {
    
        public function getDemo()
        {
            return "Demo B";
        }
    }
    lauten.
    Geändert von Spooky (06.03.2017 um 09:46 Uhr)

  11. #11
    Contao-Nutzer
    Registriert seit
    11.09.2016.
    Beiträge
    79

    Standard

    Ah verstehe, vielen Dank!

    Tatsächlich hatte ich einen Fehler, hast du recht.
    Eine Änderung in

    Code:
    namespace SubDemo;
    
    class DemoClass extends \Demo\DemoClass
    {
    
        public function getDemo()
        {
            return "Demo B";
        }
    }
    brachte den gewünschten Erfolg.
    Den Namespace hat er beim Erstellen der autoload.php automatisch hinzugefügt.

    Vielen Dank nochmal an alle, das hier hat mir sehr geholfen!

    Gruß
    *igi*

  12. #12
    Contao-Fan Avatar von PaddySD
    Registriert seit
    26.10.2016.
    Ort
    Andechs
    Beiträge
    656

    Standard

    Nur noch als kurze Ergänzung zu Spooky (saugeil erklärt übrigens!).

    PHP-Code:
    namespace Ich\SubDemo;

    class 
    SubDemo extends \Demo{} 
    • Normale Erweiterung der \Demo-Klasse
    • Ich nehme gerne einen eigenen namespace im Sinne von Name\Module, damit kann mein Klassenname auch von anderen Fremdmodulen weiterhin genutzt werden.

    Die zweite Möglichkeit ist die von Dir beschriebene (letzter Post), damit ersetzt Du Deine \Demo-Klasse mittels derer von SubDemo. Kommt eben darauf an, unter welchen Umständen Du den Aufruf tätigst. Bei der ersten Möglichkeit musst Du ja "new SubDemo()" machen, bei der zweiten Möglichkeit ist es dann automatisch eben new Demo().

    Wohlgemerkt bei Deiner Version kannst Du nach wie vor auf die Methoden der alten Klasse zugreifen, denn es gibt sogesehen zwei Demo-Klassen: \SubDemo\Demo\DemoClass und \Demo\DemoClass.

    Interessant wird es ja erst, wenn Du z.B. ein Core-Modul überschreiben willst, z.B. weil Du nicht genau weisst, wo überall der entsprechende Aufruf erfolgt. Also muss Deine Klasse die Core-Klasse ersetzen, dazu braucht man "use":
    PHP-Code:
    namespace Ich\SubDemo;

    use \
    Demo\DemoClass as myDemoClass;

    class 
    DemoClass extends myDemoClass{} 
    Jetzt stimmen nämlich auch wieder die Aufrufe egal wo, "new Demo()"... Hierbei sind automatisch alle Methoden verfügbar, nämlich die aus der ursprünglichen Klasse. Nur die Methoden, die Du in der neuen Klasse definierst, werden aus dieser genommen.

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
  •