Ankündigung

Einklappen
Keine Ankündigung bisher.

Integration eines Pluginsystems in einer HMVC Struktur

Einklappen

Neue Werbung 2019

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

  • Integration eines Pluginsystems in einer HMVC Struktur

    Für mein bevorstehendes Projekt (bereits durch ein Pflichtenheft geplant) möchte ich die Vorzüge eines Pluginsystems nutzen. Als grundlegende Programmstruktur würde ich das HMVC pattern vorschlagen, da dieses ein sehr hohes Maß an Flexibilität und Erweiterbarkeit bietet.

    Ich hatte bereits innerhalb von fünf Minuten ein triviales Pluginsystem entworfen, welches allerdings überhaupt nicht mit dem HMVC pattern in Verbindung gebracht werden kann:

    PHP-Code:
    class PluginManager
    {
        private 
    $plugins = array();
        
        public function 
    addPlugin(Plugable $plugin)
        {
            
    $this->plugins[] = $plugin;
        }
        
        public function 
    loadPlugins()
        {
            foreach (
    $this->plugins as $plugin)
            {
                
    $plugin->execute();
            }
        }
    }

    interface 
    Plugable
    {
        public function 
    execute();
    }

    class 
    Testplugin1 implements Plugable
    {
        public function 
    execute()
        {
            echo 
    "Ich bin Plugin1<br>";
        }
    }

    class 
    Testplugin2 implements Plugable
    {
        public function 
    execute()
        {
            echo 
    "Ich bin Plugin2";
        }

    Ob die im Quellcode vorhandenen Plugins verwendet werden, wird durch eine kleine Datenbanktabelle (Plugin_ID, Plugin_Name, Plugin_IsActive) entschieden und dementsprechend werden die aktivierten Plugins initiiert und die 'execute()' Methode jedes aktiven Plugins ausgeführt. Wie ihr euch bereits denken könnt verwende ich dabei Templates (Achtung: Kein Templatesystem). Diese Templates können ähnlich einer Baumstruktur beliebig tief verschachtelt werden und jedes Template bildet genau eine MVC Triade.

    Pluginsysteme bieten natürlich die Möglichkeit zur Installation / Deinstallation und Aktivierung / Deaktivierung und deren Plugins sollten möglichst unabhängig von einander sein (sonst wäre es ja kein Pluginsystem ).

    Wie kann ein Pluginsystem realisiert werden, welches auf das HMVC pattern zugeschnitten ist? Ich bitte nur um Ansätze, keine Lösungen

  • #2
    Hallo Anyone,

    an dieser Stelle - denke ich - ist die Umsetzung von HMVC der Schlüssel. In einigen Threads hatten wir hier schon einige Male das Thema Plugin bzw. Schittstelle auf GUI-Ebene besprochen. Wenn du dir diese zu Gemüte führst, wirst du sehen, wie eine Schnittstelle diesbezüglich aussehen muss.

    Da du dich bei HMVC auf GUI-Ebene befindest, wird die Schnittstelle auch eine solche sein. execute() hört sich zu sehr nach Business-Schicht an und ist die falsche Herangehensweise.
    Viele Grüße,
    Dr.E.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. Think about software design [B]before[/B] you start to write code!
    2. Discuss and review it together with [B]experts[/B]!
    3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
    4. Write [I][B]clean and reusable[/B][/I] software only!
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Kommentar


    • #3
      Zitat von dr.e. Beitrag anzeigen
      Hallo Anyone,

      an dieser Stelle - denke ich - ist die Umsetzung von HMVC der Schlüssel. In einigen Threads hatten wir hier schon einige Male das Thema Plugin bzw. Schittstelle auf GUI-Ebene besprochen. Wenn du dir diese zu Gemüte führst, wirst du sehen, wie eine Schnittstelle diesbezüglich aussehen muss.

      Da du dich bei HMVC auf GUI-Ebene befindest, wird die Schnittstelle auch eine solche sein. execute() hört sich zu sehr nach Business-Schicht an und ist die falsche Herangehensweise.
      Also ich habe mir vorhin ein Thema aus einem anderen Forum gesehen und deren Vorgehensweise scheint mir plausibler als meine. Dort werden entsprechende Pluginfunktionen registriert und einem übergeordneten Container zugewiesen.

      PHP Plugin System - gulli:board

      Würdest du das persönlich mit hooks lösen? Wie bleiben die Templates ob mit oder ohne Plugins trotzdem skalierbar?

      Danke jedenfalls schonmal für dein Feedback.

      PS: 'execute()' war erstmal nur ein ausgedachter Methodenname. Ist es übrigens normal ein paar Gehirnzellen bei solchen komplexeren Sachen zu verlieren?

      Kommentar


      • #4
        Das habe ich seit kurzem auch bei mir implementiert - In 2 Formen: 1. Als Observer-Pattern, bei dem jede Klasse von einer abstrakten Klasse abgeleitet wird, die die Observer-Funktionen beinhaltet.
        2. Eine Event-Klasse, bei der Events und dazugehörige Listener registirert werden können.

        Damit kann ich so ziemlich alles abfeiern, was kommt..

        Kommentar


        • #5
          Zitat von xm22 Beitrag anzeigen
          Das habe ich seit kurzem auch bei mir implementiert - In 2 Formen: 1. Als Observer-Pattern, bei dem jede Klasse von einer abstrakten Klasse abgeleitet wird, die die Observer-Funktionen beinhaltet.
          2. Eine Event-Klasse, bei der Events und dazugehörige Listener registirert werden können.

          Damit kann ich so ziemlich alles abfeiern, was kommt..
          Könntest du das bitte, sofern ich nicht zuviel fordere, näher ausführen? Beide Formen sind mir natürlich ein Begriff, jedoch kann ich mir die Umsetzung im Moment nicht vorstellen.

          Irgendwie habe ich das Gefühl, dass ich mich an etwas zu Großem gewagt habe, sowas ist meiner Meinung nach schon ein paar Ecken komplizierter als design patterns zu verstehen...

          Kommentar


          • #6
            Hi Anyone,

            Zitat von Anyone Beitrag anzeigen
            Also ich habe mir vorhin ein Thema aus einem anderen Forum gesehen und deren Vorgehensweise scheint mir plausibler als meine. Dort werden entsprechende Pluginfunktionen registriert und einem übergeordneten Container zugewiesen.
            Der von dir gepostete Foren-Beitrag ist mir wenig aufschlussreich. Ich fand ihn etwas wirr. Wie ich schon sagte: der Schlüssel ist die HMVC-Implementierung. Stellt sie out-of-the-box eine definierte Umgebung für einen Sub-Knoten bereit, kannst du auf dieser Basis bereits ein einfaches Plugin aufsetzen.

            Der Page-Controller des APF arbeitet genau nach diesen Vorgaben: der Subknoten des Baumes (ich nenne es mal Plugin) wird mit dem aktuellen Context, der aktuellen Sprache und den Informationen über sein Umfeld ausgestattet und in einen definierten Objekt-Lifecyle eingebunden. Als Subknoten weißt du genau, was du implementieren kannst und was wann ausgeführt wird. Mehr brauchst du IMHO erst mal nicht. Wenn es um die dynamische Einbindung von Plugins geht, so kann man sich Gedanken darüber machen, welche Informationen so ein Subknoten noch braucht oder wie man diesen "installiert". Gerade letzteres ist doch sehr einfach, wenn das Modul in einem eigenen Namespace liegt und es "einfach" per Namespace+Template importiert und ausgeführt wird. Wo, kann man ja in einer Konfiguration oder einer Datenbank speichern.

            Würdest du das persönlich mit hooks lösen? Wie bleiben die Templates ob mit oder ohne Plugins trotzdem skalierbar?
            Hooks finde ich an manchen Stellen durchaus sinnvoll, jedoch musst du beachten, dass dein Plugin Möglichkeiten hat, um auf Core-Funktionen zugreifen zu können. Aus diesem Grund finde ich den Namen "Hook" auch etwas schwierig, weil es mehr an einen "Hack" erinnert, denn an ein sauber gekapseltes Modul, dem Core-Funktionen über definierte Business-Komponenten zur Verfügung gestellt werden.
            Aus diesem Grund würde ich versuchen, eine Schnittstelle einerseits so zu realsieren, dass sie in der GUI per HMVC eingeklinkt werden kann und ihm andererseits über definierte Business-Komponenten Core-Funktionen der eigentlichen Applikation (z.B. User-Management) zur Verfügung stehen.

            PS: 'execute()' war erstmal nur ein ausgedachter Methodenname. Ist es übrigens normal ein paar Gehirnzellen bei solchen komplexeren Sachen zu verlieren?
            Du glaubst garnicht wie viele Gehirnzellen bei so komplexen Themen aktiviert werden müssen...
            Viele Grüße,
            Dr.E.

            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            1. Think about software design [B]before[/B] you start to write code!
            2. Discuss and review it together with [B]experts[/B]!
            3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
            4. Write [I][B]clean and reusable[/B][/I] software only!
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            Kommentar


            • #7
              Zitat von dr.e. Beitrag anzeigen
              Hi Anyone,


              Der von dir gepostete Foren-Beitrag ist mir wenig aufschlussreich. Ich fand ihn etwas wirr. Wie ich schon sagte: der Schlüssel ist die HMVC-Implementierung. Stellt sie out-of-the-box eine definierte Umgebung für einen Sub-Knoten bereit, kannst du auf dieser Basis bereits ein einfaches Plugin aufsetzen.

              Der Page-Controller des APF arbeitet genau nach diesen Vorgaben: der Subknoten des Baumes (ich nenne es mal Plugin) wird mit dem aktuellen Context, der aktuellen Sprache und den Informationen über sein Umfeld ausgestattet und in einen definierten Objekt-Lifecyle eingebunden. Als Subknoten weißt du genau, was du implementieren kannst und was wann ausgeführt wird. Mehr brauchst du IMHO erst mal nicht. Wenn es um die dynamische Einbindung von Plugins geht, so kann man sich Gedanken darüber machen, welche Informationen so ein Subknoten noch braucht oder wie man diesen "installiert". Gerade letzteres ist doch sehr einfach, wenn das Modul in einem eigenen Namespace liegt und es "einfach" per Namespace+Template importiert und ausgeführt wird. Wo, kann man ja in einer Konfiguration oder einer Datenbank speichern.


              Hooks finde ich an manchen Stellen durchaus sinnvoll, jedoch musst du beachten, dass dein Plugin Möglichkeiten hat, um auf Core-Funktionen zugreifen zu können. Aus diesem Grund finde ich den Namen "Hook" auch etwas schwierig, weil es mehr an einen "Hack" erinnert, denn an ein sauber gekapseltes Modul, dem Core-Funktionen über definierte Business-Komponenten zur Verfügung gestellt werden.
              Aus diesem Grund würde ich versuchen, eine Schnittstelle einerseits so zu realsieren, dass sie in der GUI per HMVC eingeklinkt werden kann und ihm andererseits über definierte Business-Komponenten Core-Funktionen der eigentlichen Applikation (z.B. User-Management) zur Verfügung stehen.


              Du glaubst garnicht wie viele Gehirnzellen bei so komplexen Themen aktiviert werden müssen...
              Vielen Dank für deinen aufschlussreichen Beitrag. Es ist wirklich manchmal gut, wenn man sich darüber im Klaren wird, was und wann etwas in Programmen getan werden muss.

              PS: Darf ich im Forum, vielleicht in einem anderen Thema, meine Grundstruktur des Klassendiagramms vorstellen und auf Feedback hoffen?

              Danke dir und schönen vierten Advent und frohe Weihnachten noch.

              Kommentar


              • #8
                Hi Anyone,

                stell deine Architektur doch hier im Thread vor. Gehört schließlich zum Thema.
                Viele Grüße,
                Dr.E.

                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                1. Think about software design [B]before[/B] you start to write code!
                2. Discuss and review it together with [B]experts[/B]!
                3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
                4. Write [I][B]clean and reusable[/B][/I] software only!
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                Kommentar


                • #9
                  Dankeschön, dennoch wird mein Klassendiagramm sowieso das schlechteste sein, was ihr jemals zu Gesicht bekommen habt.

                  http://img687.imageshack.us/i/klassendiagramm.png/

                  PS: Das Pluginsystem habe ich erstmal bewusst außenvor gelassen. Es werden auch noch Viewhelper integriert werden.

                  Kommentar


                  • #10
                    Front-Controller und Action-Controller erben von der selben Klasse? Ich weiß nicht - Die haben völlig verschiedene Aufgaben..

                    Für was sind die Stacks gut?


                    Zu der Event-Sache:

                    Die Event-Klasse ist sehr einfach aufgebaut:
                    PHP-Code:
                    <?php
                        
                    class Core_Event {
                            
                            protected static 
                    $events null;
                            
                            public static function 
                    register($event$callback) {
                                
                    self::$events[$event][] = $callback;
                            }
                            
                            public static function 
                    remove($event$processor null) {
                                if (
                    $processor === null) {
                                    unset(
                    self::$events[$event]);
                                } else if (
                    $key in_array($processorself::$events[$event])) {
                                    unset(
                    self::$events[$event][$key]);
                                }
                            }
                            
                            public static function 
                    post($event$sender) {
                                
                    $out = array();
                                
                    $args func_get_args();
                                if (isset(
                    self::$events[$event]) && is_array(self::$events[$event])) {
                                    
                                    foreach (
                    self::$events[$event] as $callback) {
                                        
                    $out[] = call_user_func_array($callback$args);
                                    }
                                }
                                
                                return 
                    $out;
                            }
                        }
                    Einen Handler/Listener zu registrieren, ist ebenfalls entsprechend einfach:
                    PHP-Code:
                    Core_Event::register('frontController.preRouteDispatch', array($object'respond')); 
                    Das Posten eines Events ebenso:
                    PHP-Code:
                    Core_Event::post(
                                    
                    'frontController.preRouteDispatch',
                                    
                    $this,
                                    
                    $this->request,
                                    
                    $this->response,
                                    
                    $this->config,
                                    
                    $this->router
                                
                    ); 
                    Dr. E. wird jetzt bemängeln , dass jeder Listener den Kontext des Events kennen muss und die Argumente, die mit dem Event übergeben werden. Ich halte das jedoch für angemessen.

                    Kommentar


                    • #11
                      Zitat von xm22 Beitrag anzeigen
                      Front-Controller und Action-Controller erben von der selben Klasse? Ich weiß nicht - Die haben völlig verschiedene Aufgaben..

                      Für was sind die Stacks gut?


                      Zu der Event-Sache:

                      Die Event-Klasse ist sehr einfach aufgebaut:
                      PHP-Code:
                      <?php
                          
                      class Core_Event {
                              
                              protected static 
                      $events null;
                              
                              public static function 
                      register($event$callback) {
                                  
                      self::$events[$event][] = $callback;
                              }
                              
                              public static function 
                      remove($event$processor null) {
                                  if (
                      $processor === null) {
                                      unset(
                      self::$events[$event]);
                                  } else if (
                      $key in_array($processorself::$events[$event])) {
                                      unset(
                      self::$events[$event][$key]);
                                  }
                              }
                              
                              public static function 
                      post($event$sender) {
                                  
                      $out = array();
                                  
                      $args func_get_args();
                                  if (isset(
                      self::$events[$event]) && is_array(self::$events[$event])) {
                                      
                                      foreach (
                      self::$events[$event] as $callback) {
                                          
                      $out[] = call_user_func_array($callback$args);
                                      }
                                  }
                                  
                                  return 
                      $out;
                              }
                          }
                      Einen Handler/Listener zu registrieren, ist ebenfalls entsprechend einfach:
                      PHP-Code:
                      Core_Event::register('frontController.preRouteDispatch', array($object'respond')); 
                      Das Posten eines Events ebenso:
                      PHP-Code:
                      Core_Event::post(
                                      
                      'frontController.preRouteDispatch',
                                      
                      $this,
                                      
                      $this->request,
                                      
                      $this->response,
                                      
                      $this->config,
                                      
                      $this->router
                                  
                      ); 
                      Dr. E. wird jetzt bemängeln , dass jeder Listener den Kontext des Events kennen muss und die Argumente, die mit dem Event übergeben werden. Ich halte das jedoch für angemessen.
                      Front-Controller und Action-Controller erben nicht, sondern implementieren dasselbe interface.

                      Für die Stacks habe ich mir irgendwie folgendes überlegt, dass jeder Stack die Möglichkeit verfügen sollte, dem Stack Elemente zuzufügen und entfernen zu können. Dennoch wollte ich mir die Möglichkeit offen halten, dass jeder Stack anders mit den Elementen umspringen kann. Also dass jeder Stack eventuell andere Methodensignaturen aufweist. Wahrscheinlich lässt sich sowas besser durch Vererbung lösen.

                      Kommentar


                      • #12
                        Mit dem Stack das habe ich schon verstanden Meine Frag bezog sich darauf, wozu Du die brauchst. Da wäre eine Registry in meinen Augen flexibler..

                        Kommentar


                        • #13
                          Zitat von xm22 Beitrag anzeigen
                          Mit dem Stack das habe ich schon verstanden Meine Frag bezog sich darauf, wozu Du die brauchst. Da wäre eine Registry in meinen Augen flexibler..
                          Stimmt, irgendwie hatte ich mit den Stacks nicht so wirklich nachgedacht.

                          Ich werde mir mal die von dir vorgestellte Event-handling-Methode näher anschauen.

                          PS: Gibt es sonst noch irgendwas austzsetzen bzw. etwas besser / einfacher / flexibler zu gestalten?
                          PPS: Warum sollte denn jeder Event-Handler nicht auch den Kontext des Events kennen? Darum sind es doch konkrete Event-Handler.

                          Kommentar


                          • #14
                            Weil es dann natürlich nicht mehr so generisch ist, wie es sein könnte. Ich habe mir das halt so gedacht, das verschiedene Events durchaus verschiedene Argumente an die Listener/Handler übergeben können.

                            Obligatorisch sind z. B. Request- und Response-Objekt aber ein Event, das nach dem Login abgefeuert wird, sollte in meinen Augen auch das Authentifizierungsobjekt bekommen...

                            Kommentar


                            • #15
                              aber ein Event, das nach dem Login abgefeuert wird, sollte in meinen Augen auch das Authentifizierungsobjekt bekommen...
                              ... und damit baust du dir wieder einen Monoliten! Es geht doch darum, die Elemente zu entkoppeln, nicht noch enger zusammen zu bringen.

                              (den Rest gibts später)
                              Viele Grüße,
                              Dr.E.

                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                              1. Think about software design [B]before[/B] you start to write code!
                              2. Discuss and review it together with [B]experts[/B]!
                              3. Choose [B]good[/B] tools (-> [URL="http://adventure-php-framework.org/Seite/088-Why-APF"]Adventure PHP Framework (APF)[/URL][URL="http://adventure-php-framework.org"][/URL])!
                              4. Write [I][B]clean and reusable[/B][/I] software only!
                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                              Kommentar

                              Lädt...
                              X