Architektur (MMVC)
Wie sich Module, Controller, Views, Modelle, der Registry und der Dispatcher gegenseitig beeinflussen.
Nibiru ist MMVC: Modell — Ansicht — Steuerung — und ein zweiter M für Modul. Die ersten drei sind vertraut; das zweite M ist, was Nibiru seinen Geschmack gibt.
Das 30-Sekunden-Gedächtnismodell
Abschnitt betitelt „Das 30-Sekunden-Gedächtnismodell“ ┌──────────────┐ │ Browser │ └──────┬───────┘ │ HTTP ▼ ┌──────────────┐ │ index.php │ └──────┬───────┘ │ require ▼ ┌──────────────┐ │ framework.php│ ◀── boots Config, Router, Engine, Smarty, └──────┬───────┘ all 28 form types, DB drivers, Auth. │ ▼ ┌──────────────┐ │ Dispatcher │ └──────┬───────┘ │ ┌───────────────┼─────────────────┐ ▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌───────────┐ │ Router │ │ Modules │ │ Auto │ └────────┘ └──────────┘ │ loader │ └───────────┘ │ ▼ ┌─────────────────────────────┐ │ applicationController.php │ │ navigationAction() │ │ <_action>Action() │ │ pageAction() │ └──────────────┬──────────────┘ │ View::assign(...) ▼ ┌──────────────┐ │ Smarty │ templates/<ctrl>.tpl + shared/* └──────────────┘Die fünf Bürger
Abschnitt betitelt „Die fünf Bürger“1. Controller (application/controller/)
Abschnitt betitelt „1. Controller (application/controller/)“Ein Controller ist eine Klasse, die von Nibiru\Adapter\Controller erbt. Der Dispatcher führt eine festgelegte Sequenz bei jedem Anfrageaufruf aus:
navigationAction()— Menüs/Brotkrumen-Daten auffüllen.<_action>Action()— nur, wenn?_action=foogesetzt ist.pageAction()— endgültige Datenzuweisung zur Renderzeit.
Nachdem alle drei zurückgekehrt sind, überreicht Display::display() die zugewiesenen Variablen an Smarty.
2. Ansichten (application/view/templates/)
Abschnitt betitelt „2. Ansichten (application/view/templates/)“Smarty .tpl-Dateien. Der Dispatcher löst <controller>.tpl automatisch auf; verschachtelte Aktionen befinden sich unter templates/<controller>/<action>.tpl. Jede über View::assign(['x' => ...]) übergebene Variable ist als {$x} verfügbar.
3. Modelle (application/model/)
Abschnitt betitelt „3. Modelle (application/model/)“Modelle werden automatisch generiert aus Ihrem Datenbankschema durch Model::__construct(false) – eine PHP-Klasse pro Tabelle. Sie erweitern Nibiru\Adapter\<Driver>\Db und bieten CRUD-Hilfsprogramme. Sie können einen generierten Modell bearbeiten und den Regenerator mit [GENERATOR] database = false deaktivieren.
4. Module (application/module/<name>/)
Abschnitt betitelt „4. Module (application/module/<name>/)“Ein Modul kapselt seine eigenen Merkmale, Plugins, Schnittstellen und Einstellungen. Der Registry entdeckt automatisch jede settings/*.ini des Moduls und macht die geparste Konfiguration über Registry::getInstance()->loadModuleConfigByName('users') zugänglich. Module können SplSubject implementieren, um das Beobachtermuster zu verwenden, was anderen Teilen des Systems erlaubt, Beobachter anzuhängen und auf Zustandsänderungen zu reagieren.
5. Singleton-Klassen, die das Universum zusammenhalten
Abschnitt betitelt „5. Singleton-Klassen, die das Universum zusammenhalten“| Singleton | Aufgabe |
|---|---|
Config::getInstance() | Liest settings.<env>.ini und fügt Modulkonfigurationen hinzu. |
Router::getInstance() | Parst die URL in Controller/Aktion/Parameter; erkennt SEO-URL-Formen. |
Registry::getInstance() | Modulentdeckung + Konfigurations-Caching. |
Dispatcher::getInstance() | Der Dirigent. dispatch::run() ist das Herzschlag Ihrer Anwendung. |
View::getInstance() | Verpackt Smarty. View::assign() ist die globale Vorlagenvariablen-Eingabebox. |
Warum MMVC und nicht MVC?
Abschnitt betitelt „Warum MMVC und nicht MVC?“Einfache MVC funktioniert, bis Ihre Controller beginnen, Logik zu teilen – Authentifizierungsprüfungen, Formularfabriken, Third-Party-API-Clients. Die üblichen Antworten sind Dienste + DI-Container, aber das ist viel Zeremonie für ein Framework zur schnellen Prototypenentwicklung.
Nibiru’s answer: Module. Ein Modul besitzt eine Domäne (users, cms, analytics, tpms-quotes), indem es seine Dienste über Plugins verfügbar macht, die Controller direkt instanziieren können:
// In a controller$user = new \Nibiru\Module\Users\Plugin\User();if (!$user->isAuthorized()) { View::forwardTo('/login');}Das Modul besitzt seine Konfiguration, seine Datenbanktabellen, seine Vorlagen und seine Formulare – und kann als Einheit entfernt werden.
Der Beobachterpattern im Einsatz
Abschnitt betitelt „Der Beobachterpattern im Einsatz“Einige Module implementieren SplSubject, sodass andere Code Teile auf Ereignisse reagieren können, ohne Kopplung. Aus der Präsentation macht das analytics-Modul auf prod.maschinen-stockert.de genau dies: jeder Controller kann einen Tracker (Matomo Plugin) mit attach() anhängen und das Analytics-Modul benachrichtigt (notify()) bei jedem Seitenaufruf, ohne dass der Controller weißt, welche Trackers existieren.
class Analytics implements \SplSubject { private \SplObjectStorage $observers; public function __construct() { $this->observers = new \SplObjectStorage(); } public function attach(\SplObserver $o): void { $this->observers->attach($o); } public function detach(\SplObserver $o): void { $this->observers->detach($o); } public function notify(): void { foreach ($this->observers as $o) { $o->update($this); } }}Was absichtlich nicht im Framework enthalten ist
Abschnitt betitelt „Was absichtlich nicht im Framework enthalten ist“- Kein DI-Container. Singletons und Plugins erfüllen die Aufgabe.
- Kein ORM. Modelle werden aus dem Schema generiert; Abfragen verwenden den
DbAdapter oder raw SQL über den aktiven Treiber. - Keine Template-Ererbung durch Twig/Blade-Tricks. Smarty
{include}ist die Kompositions-Einheit. - Kein Event-Bus.
SplSubject/SplObserversind erstklassig. - Keine ersten-Klasse Hintergrundjobs. Die CLI ist Ihr Scheduler — führen Sie ihn über cron oder systemd Timers aus.
Weniger zu lernen, mehr zu liefern.
Wo Sie weitergehen sollten
Abschnitt betitelt „Wo Sie weitergehen sollten“- Bootstrap & Dispatcher — der Lebenszyklus im Code.
- Routing — URL-zu-Controller-Zuordnungsregeln.
- Module — erstelle dein erstes Modul.