---
title: "Architectures (MMVC)"
description: "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.

<figure>
  <img src="/img/architecture-lotus.png" alt="Illustration en coupe de la couche d'exécution Nibiru dessinée comme une lotus, avec chaque pétale étiqueté comme un composant système : Routeur, Contrôleur, Vue, Modèle, Module, Registre." />
  <figcaption>La couche d'exécution Nibiru, dessinée comme une lotus.</figcaption>
</figure>

## 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

### 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 :

1. `navigationAction()` — remplir les données des menus / fil d'Ariane.
2. `<_action>Action()` — uniquement si `?_action=foo` est défini.
3. `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/`)

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/`)

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>/`)

Un module regroupe ses propres traits, plugins, interfaces et paramètres. Le [Registre](/core/registry/) 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

| 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 ?

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 :
```php
// 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

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.
```php
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

- **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 `Db` ou 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`/`SplObserver` sont 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

- [Bootstrap & Dispatcher](/core/dispatcher/) — le cycle de vie en code.
- [Routing](/core/routing/) — règles de mappage URL → contrôleur.
- [Modules](/core/modules/) — construisez votre premier.
