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

<figure>
  <img src="/img/architecture-lotus.png" alt="Querschnittsillustration der Nibiru-Laufzeit als Lotus, wobei jede Blattfläche als Systemkomponente beschriftet ist: Router, Controller, View, Model, Modul, Registry." />
  <figcaption>Die Nibiru-Laufzeit als Lotus.</figcaption>
</figure>

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

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

1. `navigationAction()` — Menüs/Brotkrumen-Daten auffüllen.
2. `<_action>Action()` — nur, wenn `?_action=foo` gesetzt ist.
3. `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/`)

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

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

Ein Modul kapselt **seine eigenen** Merkmale, Plugins, Schnittstellen und Einstellungen. Der [Registry](/core/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

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

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

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.
```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); }
    }
}
```
## 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 `Db` Adapter oder raw SQL über den aktiven Treiber.
- **Keine Template-Ererbung durch Twig/Blade-Tricks.** Smarty `{include}` ist die Kompositions-Einheit.
- **Kein Event-Bus.** `SplSubject`/`SplObserver` sind 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

- [Bootstrap & Dispatcher](/core/dispatcher/) — der Lebenszyklus im Code.
- [Routing](/core/routing/) — URL-zu-Controller-Zuordnungsregeln.
- [Module](/core/modules/) — erstelle dein erstes Modul.
