Module
Erstellen von Nibiru-Modulen — das zweite M in MMVC. Merkmale, Plugins, Schnittstellen, Einstellungen, Beobachter.
Ein Modul ist eine selbstständige Domänen-Einheit. Es besitzt seine Konfiguration, seine Plugins (Dienste), seine Traits (wiederverwendbare Methoden), seine Schnittstellen und optional einen eigenen MVC-Slice. Module sind die Art und Weise, wie Nibiru das fat-controller-Problem ohne einen Dienstcontainer vermeidet.
Anatomie
Abschnitt betitelt „Anatomie“application/module/<name>/├── <name>.php # main class (implements IModule, optionally SplSubject)├── interfaces/ # contracts for plugins / external consumers│ └── <name>.php├── plugins/ # stateless services usable from controllers│ ├── <thing>.php│ └── <other>.php├── settings/ # auto-discovered .ini files│ ├── <name>.ini│ └── <name>.production.ini└── traits/ # reusable method groups └── <name>.phpDer Registry durchsucht application/module/ beim Starten, entdeckt die jeweiligen Module in settings/*.ini, analysiert den Abschnitt, der mit dem Modulnamen (in Großbuchstaben) übereinstimmt, und speichert ihn für den Abruf über Registry::getInstance()->loadModuleConfigByName('users').
Ein minimales Modul
Abschnitt betitelt „Ein minimales Modul“<?phpnamespace Nibiru\Module\Users;
use Nibiru\Module as ModuleAdapter;use Nibiru\Interfaces\IModule;use Nibiru\Registry;
class Users extends ModuleAdapter implements IModule, \SplSubject{ use Traits\Users;
const CONFIG_MODULE_NAME = 'users';
protected static \stdClass $usersRegistry; protected \SplObjectStorage $observers;
public function __construct() { $this->setUsersRegistry(); $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); } }
protected function setUsersRegistry(): void { self::$usersRegistry = Registry::getInstance() ->loadModuleConfigByName(self::CONFIG_MODULE_NAME); }}Die IModule Schnittstelle ist absichtlich ein Marker – der tatsächliche Verhalten befindet sich vollständig in Ihren Traits und Plugins.
Plugins: Zustandslose Dienste
Abschnitt betitelt „Plugins: Zustandslose Dienste“Ein Plugin ist eine Klasse, die Controller instanziieren können, um auf Modulfunktionen zuzugreifen:
<?phpnamespace Nibiru\Module\Users\Plugin;
use Nibiru\Module\Users\Users;use Nibiru\Pdo;
class User extends Users{ public function isAuthorized(): bool { return isset($_SESSION['auth']['user_id']); }
public function checkForStandardUser(): bool { return $this->isAuthorized() && ($_SESSION['auth']['role'] ?? '') === 'standard'; }}In einem Controller:
$this->user = new \Nibiru\Module\Users\Plugin\User();if (!$this->user->isAuthorized()) { View::forwardTo('/login');}Plugins erben von der Modulklasse und teilen daher Zugriff auf den Registrierungsmechanismus, die Einstellungen und das Beobachtergerüst.
Merkmale: wiederverwendbare Methoden
Abschnitt betitelt „Merkmale: wiederverwendbare Methoden“Ein Trait trägt wiederverwendbare Methodenkörper, die die Modulklassen benötigen. Häufiges Muster: Form-Factories.
<?phpnamespace Nibiru\Module\Users\Traits;
use Nibiru\Form;
trait Users{ public function loginForm(): string { Form::create(); Form::addOpenDiv(['class' => 'form-group']); Form::addInputTypeText([ 'class' => 'form-control', 'name' => 'login', 'placeholder' => 'Username', ]); Form::addCloseDiv(); Form::addOpenDiv(['class' => 'form-group']); Form::addInputTypePassword([ 'class' => 'form-control', 'name' => 'password', 'placeholder' => 'Password', ]); Form::addCloseDiv(); return Form::addForm([ 'method' => 'POST', 'action' => '/login', 'name' => 'loginForm', ]); }}Die Hauptklasse Users bringt es über use Traits\Users; ein.
Modul-Einstellungen (INI)
Abschnitt betitelt „Modul-Einstellungen (INI)“Jeder Modul kann seine eigenen INI-Dateien haben. Der Registrierungsmechanismus analysiert jede *.ini-Datei im Verzeichnis settings/ und sucht nach einem Abschnitt, der den Namen des Moduls (in Großbuchstaben) trägt:
; application/module/users/settings/users.ini[USERS]session.lifetime = 7200password.min.length = 12allowed.roles[] = "admin"allowed.roles[] = "editor"allowed.roles[] = "standard"Lesen Sie es von überall aus:
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('users');$cfg->session_lifetime; / 7200$cfg->password_min_length; / 12$cfg->allowed_roles; / [admin, editor, standard]Umgebungsüberschreibungen: Eine Datei mit dem Namen users.production.ini wird vorzugsweise gegenüber users.ini verwendet, wenn APPLICATION_ENV=production.
Das Beobachter-Muster
Abschnitt betitelt „Das Beobachter-Muster“Module, die SplSubject implementieren, können Ereignisse an angehängte Beobachter übertragen, ohne mit ihnen gekoppelt zu sein. Aus der Präsentation meldet das Modul analytics jedem angehängten Tracker bei jeder Seitenansicht:
// in a controller$analytics = new \Nibiru\Module\Analytics\Analytics();$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Matomo());$analytics->attach(new \Nibiru\Module\Analytics\Plugin\Plausible());
$analytics->trackPageView(); / internally calls notify()Jeder Beobachter erhält die Analytics-Instanz und zieht die Ereignisdaten aus, über die er sich interessiert.
Echte Produktionsmodule
Abschnitt betitelt „Echte Produktionsmodule“Von den Showcase-Anwendungen:
auth(TPMS) — Sitzungsverwaltung, QR-Code-Anmeldung, rollenbasierte Zugriffskontrolle. ImplementiertSplSubject, sodass Anmelde-/Abmeldeereignisse an Protokollierungs- und Überwachungsmodule weitergegeben werden können.cms(prod.maschinen-stockert.de) — Inhaltsverwaltung, indiziert durch Controller-Pfad + Sprache. Ermöglicht es Nicht-Entwicklern, die Seitenkopien zu aktualisieren.graph_mail(TPMS) — Microsoft Graph API-Wrapper für transaktionale E-Mails.pdfgenerator(prod.maschinen-stockert.de) — Generiert Maschinenkataloge aus DB-gesteuerten Vorlagen.machineryscout— Elasticsearch-Indexverwaltung mit Merkmalen für Indizierung, Abfrage und erneute Indizierung.assetmanager— zentrales CSS/JS-Pipeline, verwendet zum Wechseln von Themen je nach Sprache.analytics— beobachtungsgetriebene Tracker-Ausbreitung (Matomo usw.).
Modulregistrierung: Wie das Framework Ihr Modul findet
Abschnitt betitelt „Modulregistrierung: Wie das Framework Ihr Modul findet“Ein Modulordner auf der Festplatte ist erforderlich, aber nicht ausreichend. Das Framework muss auch wissen, wie es geladen wird – das geschieht mit drei Positionierungsarrays in Ihrer [AUTOLOADER]-Konfiguration:
; application/settings/config/settings.development.ini
[AUTOLOADER]iface.pos[] = "users" ; load application/module/users/interfaces/iface.pos[] = "billing" ; load application/module/billing/interfaces/trait.pos[] = "users" ; load application/module/users/traits/trait.pos[] = "billing"class.pos[] = "users" ; load application/module/users/users.phpclass.pos[] = "billing"class.plugin.pos[] = "" ; reservedDie Namen sind kleinbuchstabeigeordnete Ordnername, genau wie sie unter application/module/ erscheinen. Der Frameworks Auto::loader() (aufgerufen vom Dispatcher) durchläuft jede Modul in der Reihenfolge und erfordert seine Dateien.
Konvention für den Plugin-Namespace
Abschnitt betitelt „Konvention für den Plugin-Namespace“Pluginklassen liegen im Plural-Namespace Plugins:
namespace Nibiru\Module\Billing\Plugins; / ← pluralclass Invoice extends \Nibiru\Module\Billing\Billing { /* ... */ }Namespace und Klassenname nicht übereinstimmen und es treten Autoloader-Fehlschläge auf. Der CLI-Scaffold-Befehl (./nibiru -m billing) generiert den richtigen Namespace für Sie.
Einstellungensermittlung
Abschnitt betitelt „Einstellungensermittlung“Sie registrieren Ihre Modul-INI-Dateien nicht — der Registry entdeckt sie automatisch, indem er application/module/<name>/settings/*.ini durchläuft, nachdem [AUTOLOADER] die Modulklassen lädt. Jede Sektion [<MODULE>] (in Großbuchstaben) in einer INI wird zur Verfügung gestellt als:
$cfg = \Nibiru\Registry::getInstance()->loadModuleConfigByName('billing');$cfg->invoice_prefix; / [BILLING] invoice.prefix → propertyDer Registrierungsmodul bevorzugt <Modul>.<Umgebung>.ini (z.B. billing.production.ini), wenn APPLICATION_ENV übereinstimmt.
Migrationen
Abschnitt betitelt „Migrationen“Wenn Ihr Modul Datenbanktabellen hat, fügen Sie SQL-Dateien in application/settings/config/database/ ein, die nummeriert sind und sich auf den bestehenden Bereich beziehen. Konvention des AI-Moduls:
200-ai_rag_collection.sql201-ai_rag_chunk.sql202-ai_conversation.sql203-ai_message.sqlFühren Sie mit ./nibiru -mi local aus. Das Framework generiert automatisch Modelle in application/model/<table>.php, wenn [GENERATOR] database = true gesetzt ist, bereit zur Verwendung über \Nibiru\Pdo::fetchAll(…).
Ein Modul generieren
Abschnitt betitelt „Ein Modul generieren“./nibiru -m billingSkelette:
application/module/billing/├── billing.php├── interfaces/billing.php├── plugins/├── settings/billing.ini└── traits/Fügen Sie den Schalter -g (./nibiru -m billing -g) hinzu, wenn Sie Graylog-Protokollierungshooks vordefiniert in die Struktur einfügen möchten.
Wenn ein Modul nicht erstellt werden sollte
Abschnitt betitelt „Wenn ein Modul nicht erstellt werden sollte“Verwenden Sie nicht jede Controller-Klasse als Modul. Der Schwellenwert ist: haben Sie mindestens ein Trait, eine Erweiterung und einen INI-Schlüssel? Wenn ja, verdient es sein eigenes Modulverzeichnis. Wenn nein, reicht ein freigegebener Trait-Datei oder eine kleine Hilfsdatei in application/lib/.