Architectures (MMVC)
Comment les modules, contrôleurs, vues, modèles, le registre et le dispatcheur s'entourent mutuellement.
Nibiru est MMVC : Modèle — Vue — Contrôleur — et une seconde M pour Module. Les trois premiers sont familiers ; la deuxième M donne à Nibiru son goût.
Le modèle mental en 30 secondes
Section intitulée « Le modèle mental en 30 secondes » ┌──────────────┐ │ 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/* └──────────────┘Les cinq citoyens
Section intitulée « Les cinq citoyens »1. Contrôleurs (application/controller/)
Section intitulée « 1. Contrôleurs (application/controller/) »Un contrôleur est une classe qui étend Nibiru\Adapter\Controller. Le dispatcheur invoque une séquence fixe à chaque requête :
navigationAction()— remplir les données des menus / fil d’Ariane.<_action>Action()— uniquement si?_action=fooest défini.pageAction()— attribution finale des données au moment du rendu.
Après le retour des trois, Display::display() transmet les variables assignées à Smarty.
2. Vues (application/view/templates/)
Section intitulée « 2. Vues (application/view/templates/) »Fichiers Smarty .tpl. Le dispatcheur résout automatiquement <controller>.tpl; les actions imbriquées se trouvent sous templates/<controller>/<action>.tpl. Chaque variable transmise via View::assign(['x' => ...]) est disponible sous la forme {$x}.
3. Modèles (application/model/)
Section intitulée « 3. Modèles (application/model/) »Les modèles sont générés automatiquement à partir de votre schéma de base de données par Model::__construct(false) — une classe PHP par table. Ils étendent Nibiru\Adapter\<Driver>\Db et exposent des assistants CRUD. Vous pouvez éditer manuellement un modèle généré et désactiver le régénérateur avec [GENERATOR] database = false.
4. Modules (application/module/<name>/)
Section intitulée « 4. Modules (application/module/<name>/) »Un module regroupe ses propres traits, plugins, interfaces et paramètres. Le Registre détecte automatiquement chaque fichier de configuration settings/*.ini des modules et expose la configuration analysée via Registry::getInstance()->loadModuleConfigByName('users'). Les modules peuvent implémenter SplSubject pour le modèle observateur, permettant à d’autres parties du système d’attacher des observateurs et de réagir aux changements d’état.
5. Les singletons qui maintiennent l’univers ensemble
Section intitulée « 5. Les singletons qui maintiennent l’univers ensemble »| Singleton | Tâche |
|---|---|
Config::getInstance() | Lit settings.<env>.ini et fusionne les configurations de module. |
Router::getInstance() | Analyse l’URL en contrôleur/action/paramètres ; reconnaît les formes d’URL SEO. |
Registry::getInstance() | Découverte des modules + mise en cache des configurations. |
Dispatcher::getInstance() | Le chef d’orchestre. dispatch::run() est le battement cardiaque de votre application. |
View::getInstance() | Encapsule Smarty. View::assign() est la boîte aux lettres des variables de modèle globales. |
Pourquoi MMVC et non MVC ?
Section intitulée « Pourquoi MMVC et non MVC ? »Le simple MVC fonctionne jusqu’à ce que vos contrôleurs commencent à partager de la logique : des vérifications d’authentification, des fabriques de formulaires, des clients d’API tierces. Les réponses habituelles sont des services + un conteneur DI, mais c’est beaucoup de cérémonie pour un cadre de prototypage rapide.
La réponse de Nibiru : modules. Un module possède un domaine (utilisateurs, cms, analytiques, tpms-citations), exposant ses services via des contrôleurs de plug-ins que les instances peuvent instancier directement :
// In a controller$user = new \Nibiru\Module\Users\Plugin\User();if (!$user->isAuthorized()) { View::forwardTo('/login');}Le module possède sa configuration, ses tables de base de données, ses modèles, ses formulaires — et peut être supprimé en tant qu’unité.
Le modèle observateur, en pratique
Section intitulée « Le modèle observateur, en pratique »Certains modules implémentent SplSubject afin que d’autres parties de code puissent réagir aux événements sans couplage. À partir du showcase, le module analytics sur prod.maschinen-stockert.de fait exactement cela : n’importe quel contrôleur peut attach() un suivi (plugin Matomo) et le module d’analyse notify() à chaque affichage de page, sans que le contrôleur ne sache quels suivis existent.
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); } }}Ce qui n’est pas délibérément inclus dans le cadre
Section intitulée « Ce qui n’est pas délibérément inclus dans le cadre »- Aucun conteneur DI. Les singletons et les plugins suffisent.
- Aucune ORM. Les modèles sont générés à partir du schéma ; les requêtes utilisent l’adaptateur
Dbou le SQL brut via le pilote actif. - Aucune héritage de modèle via des astuces Twig/Blade. Smarty
{include}est l’unité de composition. - Aucun bus d’événements.
SplSubject/SplObserversont en première classe. - Aucuns travaux d’arrière-plan de première classe. La CLI est votre planificateur — utilisez-le avec cron ou systemd timers.
Moins à apprendre, plus à livrer.
Où aller ensuite
Section intitulée « Où aller ensuite »- Bootstrap & Dispatcher — le cycle de vie en code.
- Routing — règles de mappage URL → contrôleur.
- Modules — construisez votre premier.