---
title: "Pourquoi Nibiru et non Laravel ?"
description: "Cinq choses que Nibiru fait différemment de Laravel et Symfony — chacune appuyée par du code réel en production."
---

La plupart des comparaisons de frameworks PHP sont subjectives. Cette comparaison est filtrable avec `grep`.

Les cinq différences ci-dessous proviennent d'un site de génération de revenus réel : **[maschinen-stockert.de](/en/showcase/projects/)** — un marché multilingue pour l'équipement industriel. **36 contrôleurs, 18 modules, 348 modèles, 161 migrations SQL, 37 369 lignes de PHP** dans deux dépôts. Chaque affirmation fait référence à un fichier:ligne au sein des bases de code, donc vous pouvez la vérifier.

Si vous avez travaillé avec Laravel ou Symfony, vous reconnaîtrez les modèles que Nibiru *n'a pas*. C'est le but.

---

## 1. Couche CMS intégrée dans le cadre

Dans Laravel, le contenu des pages se trouve dans les fichiers Blade (`{{ __('page.title') }}`) ou dans un fichier JSON de traduction. Pour le modifier, un développeur édite un fichier et déploie. Dans Nibiru, le contenu des pages se trouve dans la base de données, clé par `<controller>/<action>` + langue, et les éditeurs le mettent à jour depuis l'interface d'administration **sans toucher au code**.
```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']
        ]);
    }
}
```
**Effet global** : le marketing modifie un titre dans l'éditeur, rafraîchit la page et déploie. Aucune demande de tirage (PR), aucun déploiement, aucun développeur impliqué. Ce n'est pas une extension du CMS — le module `Cms` du framework est intégré.

→ Consultez [Modules](/fr/core/modules/) pour voir comment le module CMS se compose.

---

## 2. Les modules sont composés par des traits, pas par un conteneur de services

La réponse de Laravel à une classe de 5 000 lignes est les fournisseurs de services et l'injection de dépendances. La réponse de Nibiru est **les traits**.

Le module CMS sur `maschinen-stockert.de` est construit à partir de **13 traits**, chacun ayant une seule responsabilité — `CmsStore`, `TextsForm`, `PageBuilderForm`, `CmsPageStructureModifier`, `FormElements`, … La classe principale `Cms` fait 30 lignes qui les rassemblent. Ajouter une nouvelle fonctionnalité est *"créer un trait, l'inclure, c'est fait."*
```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
}
```
**Effet net**: aucune injection de constructeur, aucune inscription auprès du fournisseur de services, aucun appel à `bind()` / `singleton()` dans un fichier de configuration. Un nouveau développeur peut rechercher le nom du trait et voir tous les appels.

---

## 3. Requête SQL directe avec agrégation JSON, pas un ORM

Eloquent et Doctrine sont équipés d'une taxe : chaque relation chargée est potentiellement une requête N+1, et chaque agrégation poussée dans PHP est une mémoire gaspillée. Nibiru repose sur la base de données où elle en a le plus besoin.
```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;
```
Une requête. Des attributs et des images agrégés en JSON, indexés à partir de la base de données. Le résultat s'inscrit directement dans Elasticsearch, prêt à alimenter des requêtes de plage sur des dimensions comme *"2500 × 1200 mm"*.

**Effet net** : Les problèmes N+1 n'existent pas. Auditables, profilables et rapides.

→ Consultez [Base de données et migrations](/fr/core/database/) pour l'adaptateur `Pdo` qui exécute des requêtes comme celle-ci.

---

## 4. Contrôle d'accès basé sur les rôles sans chaînes de middlewares

Dans Laravel, l'autorisation est une pile : `auth` middleware → classe de politique → porte → contrôleur. Dans Nibiru, c'est trois lignes dans le constructeur :
```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()` charge le jeu de rôles / permissions pour la session actuelle. `$this->user->validate()` vérifie que la session est valide. Si l'un d'eux échoue, la requête retourne la page de connexion. Les vérifications par action (`$this->acl->can('edit', 'pages')`) se trouvent dans les actions qui en ont besoin.

Le contrôleur API adopte une approche inverse : une liste blanche des points de terminaison publics dans le constructeur, l'authentification requise pour tout le reste.
```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();
}
```
**Effet global** : l'autorisation est une expression trouvable par grep. Aucun bug de tri du middleware. Aucune mystère comme "pourquoi cet endpoint est-il public ?".

→ Consultez [Auth](/fr/core/auth/) pour plus de détails sur les sessions et le contrôle d'accès (ACL).

---

## 5. Le modèle observateur, pas le distributeur d'événements

Les événements de Laravel sont diffusés via un distributeur avec des fermetures, des écouteurs et des enregistrements de tâches en file d'attente. Nibiru utilise les interfaces `SplSubject` / `SplObserver` de la bibliothèque standard PHP. Même modèle, deux interfaces, sans couche d'abstraction.
```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.
    }
}
```
**Effet net**: les changements d'état sont synchrones, déterministes et débogables. Aucun travailleur de file d'attente. Pas de mystère du type "a-t-on entendu l'écouteur ?". Ajoutez un observateur dans le contrôleur et il est branché.

→ Consultez [Modules](/fr/core/modules/#le-motif-observateur) pour le motif.

---

## Ce que cela vous donne, en deux phrases

Un développeur solo ou une petite équipe peut construire et *exploiter* une véritable application de production — comme celle vendant des machines industrielles dans 12 pays — avec **moins de framework à apprendre**, **moins d'abstractions à déboguer** et **moins de cérémonie par fonctionnalité**. Le compromis est que si vous préférez que le framework cache chaque requête de base de données et orchestre chaque événement, vous serez plus heureux ailleurs.

Si vous préférez voir votre code, prenez-le.

→ [Lisez la présentation →](/fr/presentation/projets/)
