---
title: "Warum Nibiru und nicht Laravel?"
description: "Fünf Dinge, die Nibiru anders als Laravel und Symfony macht – jeweils unterpuntet durch echten Produktionscode."
---

Die meisten Vergleiche von PHP-Frameworks sind eher subjektiv. Dieser ist nachvollziehbar.

Die fünf Unterschiedsmaker unten stammen aus einer realen Einnahmengenerierungswebsite: **[maschinen-stockert.de](/en/showcase/projects/)** — einem multilingualen Industriemaschinen-Marktplatz. **36 Controller, 18 Module, 348 Vorlagen, 161 SQL-Migrationen, 37.369 Zeilen PHP** über zwei Repositories. Jede Behauptung verweist auf einen Datei:Zeilenverweis innerhalb der Codebasen, sodass Sie es überprüfen können.

Wenn Sie mit Laravel oder Symfony gearbeitet haben, werden Sie die Muster erkennen, die Nibiru nicht hat. Das ist der Punkt.

---

## 1. Integrierte CMS-Schicht in das Framework

In Laravel befindet sich die Seitenkopie in Blade-Dateien (`{{ __('page.title') }}`) oder in der Übersetzungsdatei JSON. Um sie zu ändern, bearbeitet ein Entwickler eine Datei und führt einen Deployment durch. In Nibiru befindet sich die Seitenkopie in der Datenbank, mit dem Schlüssel `<controller>/<action>` + Sprache, und Redakteure aktualisieren sie über die Admin-Oberfläche **ohne Code zu berühren**.
```php
// data.maschinen-stockert.de/application/controller/maschineController.php
public function pageAction()
{
    $controllerPath = $this->getController() . '/' . $this->getRequest('_action', 'page');

    foreach (Cms::init($this->getController())
                 ->loadCmsTemplateTextsByControllerPath($controllerPath, $this->language)
             as $t) {
        View::assign([
            $t['cms_template_texts_text_identifier']
                => $t['cms_template_texts_text_content']
        ]);
    }
}
```
**Gesamtwirkung**: Marketing ändert einen Headline im Editor, aktualisiert die Seite und veröffentlicht. Kein PR, kein Deployment, kein Entwickler im Begriff. Das ist kein CMS-Plugin – das Modul `Cms` des Frameworks ist eingebaut.

→ Siehe [Module](/de/core/modules/) für die Art und Weise, wie das CMS-Modul sich zusammensetzt.

---

## 2. Module bestehen aus Merkmalen (Traits), nicht aus einem Dienstcontainer

Laravels Antwort auf eine Klasse mit 5.000 Zeilen sind Service-Provider und Dependency Injection. Nibirus Antwort ist **Traits**.

Das CMS-Modul auf `maschinen-stockert.de` besteht aus **13 Merkmalen**, wobei jedes ein einzelner Verantwortungsbereich ist — `CmsStore`, `TextsForm`, `PageBuilderForm`, `CmsPageStructureModifier`, `FormElements`, … Die Hauptklasse `Cms` umfasst 30 Zeilen, die sie zusammenfügen. Das Hinzufügen einer neuen Funktion lautet *"eine Merkmale erstellen, einbinden, fertig."*
```php
// application/module/cms/cms.php
class Cms implements Interfaces\Cms, SplSubject
{
    use Traits\CmsStore;
    use Traits\TextsForm;
    use Traits\PageBuilderForm;
    use Traits\CmsPageStructureModifier;
    use Traits\FormElements;
    // …8 more traits
}
```
**Gesamtwirkung**: keine Konstruktor-Injektion, keine Dienstleistungsanbieterregistrierung, keine Aufrufe von `bind()` / `singleton()` in einer Konfigurationsdatei. Ein neuer Entwickler kann nach dem Trait-Namen suchen und alle Aufrufer sehen.

---

## 3. Direkte SQL mit JSON-Aggregation, keine ORM

Eloquent und Doctrine verpflichten zu einer Gebühr: jede geladene Beziehung könnte eine N+1-Abfrage sein, und jede Aggregation, die in PHP übertragen wird, ist Speicher verschwendet. Nibiru setzt sich auf die Datenbank, wo sie stark ist.
```sql
-- application/module/machineryscout/traits/machinesElasticSearch.php
SELECT
    m.ms_machines_id AS machine_id,
    m.ms_machines_name AS machine_name,
    JSON_ARRAYAGG(
        DISTINCT JSON_OBJECT(
            'attribute_name',  ma.ms_machine_attributes_attribute_name,
            'attribute_value', mav.ms_machine_attribute_values_value,
            'attribute_type',  ma.ms_machine_attributes_attribute_type
        )
    ) AS attributes,
    JSON_ARRAYAGG(DISTINCT mi.ms_machine_images_filename
        ORDER BY mi.ms_machine_images_sort_order ASC) AS images
FROM ms_machines m
LEFT JOIN ms_machine_attribute_values mav ON mav.ms_machine_attribute_values_machine_id = m.ms_machines_id
LEFT JOIN ms_machine_attributes ma ON mav.ms_machine_attribute_values_attribute_id = ma.ms_machine_attributes_id
LEFT JOIN ms_machine_images mi ON mi.ms_machines_id = m.ms_machines_id
WHERE m.ms_active = 1
GROUP BY m.ms_machines_id;
```
Eine Anfrage. Aggregierte JSON-Attribute und Bilder, indiziert aus der Datenbank. Das Ergebnis fließt direkt in Elasticsearch ein, bereit, Bereichsanfragen auf Maße wie *"2500 × 1200 mm"* zu unterstützen.

**Gesamtwirkung**: Probleme des Typs N+1 existieren nicht. Überprüfbar, profilierbar und schnell.

→ Siehe [Datenbank & Migrationen](/de/core/database/) für den `Pdo` Adapter, der Abfragen wie diese ausführt.

---

## 4. Rollenbasierte ACL ohne Middleware-Ketten

In Laravel ist die Autorisierung ein Stack: `auth` Middleware → Policy-Klasse → Gate → Controller. In Nibiru sind es drei Zeilen im Konstruktor:
```php
// data.maschinen-stockert.de/application/controller/adminController.php
public function __construct() {
    parent::__construct();
    $this->user = new User();
    $this->acl  = new Acl();
    $this->acl->init();
    $this->user->validate();
}
```
`$this->acl->init()` lädt die Rollen-/Berechtigungsmenge für die aktuelle Sitzung. `$this->user->validate()` überprüft, ob die Sitzung gültig ist. Wenn einer dieser Schritte fehlschlägt, wird die Anfrage die Login-Seite zurückgeben. Berechtigungsprüfungen pro Aktion (`$this->acl->can('edit', 'pages')`) befinden sich in den Aktionen, die sie benötigen.

Der API-Controller nimmt den umgekehrten Ansatz: eine Whitelist öffentlicher Endpunkte im Konstruktor und Authentifizierung für alles andere.
```php
// public endpoints can be listed up-front, auth wraps the rest.
if (in_array($action, ['category', 'machines', 'ollama', 'team'])) {
    // public, skip auth
} else {
    $this->user = new User();
    $this->acl  = new Acl();
    $this->acl->init();
    $this->user->validate();
}
```
**Gesamtwirkung**: Die Autorisierung ist ein durchsuchbares Ausdruck. Keine Probleme mit der Reihenfolge des Middlewares. Keine Geheimnisse wie „Warum ist dieser Endpunkt öffentlich?“.

→ Siehe [Auth](/de/core/auth/) für Details zu Sitzungen und Zugriffssteuerung.

---

## 5. Beobachtermuster, nicht Ereignisdispatcher

Die Ereignisse von Laravel werden über einen Dispatcher mit Schließlinsen, Listenern und Aufzeichnungen für wartige Jobs ausgegeben. Nibiru verwendet die PHP-Standardbibliothek-Schnittstellen `SplSubject` / `SplObserver`. Gleiches Muster, zwei Schnittstellen, keine Abstraktionsebene.
```php
class Machineryscout implements IModule, \SplSubject
{
    private \SplObjectStorage $observers;

    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);
    }

    public function indexMachines(): void {
        // …do the work…
        $this->notify();   // analytics, cache invalidator, audit log all see it.
    }
}
```
**Gesamtwirkung**: Zustandsänderungen sind synchron, deterministisch und debugbar. Kein Queue Worker. Keine "hat der Listener gefeuert?" Geheimnis. Fügen Sie einen Observer im Controller hinzu, und er wird verbunden.

→ Siehe [Module](/de/core/modules/#der-beobachtermuster) für das Muster.

---

## Was Sie damit erhalten, in zwei Sätzen

Ein einzelner Entwickler oder eine kleine Team kann eine echte Produktions-App bauen und *betreiben* – wie zum Beispiel eine, die Maschinen in 12 Ländern verkauft – mit **weniger Frameworks zu lernen**, **weniger Abstraktionen zu debuggen** und **weniger Zeremonien pro Funktion**. Der Kompromiss ist, dass Sie lieber möchten, dass das Framework jede Datenbankabfrage verbirgt und jedes Ereignis orchestriert, dann sind Sie an einem anderen Ort glücklicher.

Wenn Sie lieber Ihren Code sehen möchten, nehmen Sie ihn.

→ [Die Präsentation ansehen →](/de/praesentation/projekte/)
