---
title: "Modelos"
description: "Cómo Nibiru genera automáticamente las clases de modelos a partir de su esquema de base de datos y cómo extenderlas."
---

La capa de modelos de Nibiru es *primero-esquema*. No escribes los modelos a mano — el marco lee tu base de datos y genera una clase PHP por tabla en cada inicio.

## Cómo funciona la generación

Cuando `[GENERATOR] database = true` en tu INI, el despachador ejecuta `new Model(false)` en cada solicitud, lo que hace que:

1. Conecta con el controlador activo.
2. Enumera las tablas en la base de datos configurada (`information_schema.tables` para PG, `SHOW TABLES` para MySQL).
3. Para cada tabla, escribe `application/model/<table>.php` que contiene una clase que extiende el adaptador `Db` relevante e incorpora una constante `TABLE` que describe las columnas.

Volver a ejecutar es barato: el generador sobrescribe solo cuando el esquema ha cambiado, por lo que los modelos registrados mantienen sus métodos manuscritos *si* cambias `database = false` después del primer ejecución.
```ini
[GENERATOR]
database          = true     ; regenerate models on each request
database.overwrite = true    ; if false, generator won't touch existing files
```
En producción, establece `database = false` para que los modelos no se regeneren en cada solicitud.

## Un modelo generado

Para una tabla `users` con columnas `user_id, user_login, user_pass, user_email`:
```php
<?php
namespace Nibiru\Model;
use Nibiru\Adapter\MySQL\Db;

class users extends Db
{
    const TABLE = [
        'table' => 'users',
        'field' => [
            'user_id'    => 'user_id',
            'user_login' => 'user_login',
            'user_pass'  => 'user_pass',
            'user_email' => 'user_email',
        ],
    ];

    public function __construct() {
        self::initTable(self::TABLE);
    }
}
```
El adaptador `Db` te proporciona simples ayudantes CRUD a través de `Pdo::` (o el controlador activo):
```php
$users = new \Nibiru\Model\users();

// Read by primary key
$row = \Nibiru\Pdo::fetchRowInArrayById('users', ['user_id' => 42]);

// Read all
$all = \Nibiru\Pdo::fetchAll('SELECT * FROM users WHERE user_account_active = 1');

// Insert
\Nibiru\Pdo::insert('users', [
    'user_login' => 'marduk',
    'user_email' => 'marduk@nibiru.local',
]);

// Update
\Nibiru\Pdo::update('users',
    ['user_email' => 'new@nibiru.local'],
    ['user_id' => 42]);

// Delete
\Nibiru\Pdo::delete('users', ['user_id' => 42]);
```
## Consultas personalizadas

La clase generada es una clase PHP simple — añade métodos libremente:
```php
namespace Nibiru\Model;
use Nibiru\Adapter\MySQL\Db;
use Nibiru\Pdo;

class documentation extends Db
{
    const TABLE = [
        'table' => 'documentation',
        'field' => [
            'id' => 'id', 'title' => 'title', 'slug' => 'slug',
            'content' => 'content', 'category' => 'category',
            'version' => 'version',
        ],
    ];

    public function __construct() { self::initTable(self::TABLE); }

    public function getBySlug(string $slug): ?array {
        return Pdo::fetchRowInArrayById(
            self::TABLE['table'],
            [self::TABLE['field']['slug'] => $slug]
        ) ?: null;
    }

    public function search(string $query): array {
        $sql = 'SELECT * FROM ' . self::TABLE['table']
             . ' WHERE title LIKE :q OR content LIKE :q ORDER BY title';
        return Pdo::fetchAll($sql, [':q' => '%' . $query . '%']);
    }
}
```
Si el generador se ejecuta nuevamente con `database.overwrite = true`, reemplazará este archivo. Mantenga los métodos personalizados en una clase secundaria o establezca `database.overwrite = false` después de la primera generación.

## Patrón: modelo delgado + módulo de complemento

Para dominios complejos (autenticación, facturación, análisis), las aplicaciones de demostración colocan los métodos de consulta en un **módulo de complemento** en lugar del modelo sin procesar. El complemento posee las reglas de negocio; el modelo es solo un identificador tipado para la tabla:
```
application/module/users/
├── plugins/
│   └── user.php         # User::isAuthorized(), User::loginForm(), …
└── traits/
    └── userForm.php
``````php
namespace Nibiru\Module\Users\Plugin;
use Nibiru\Model\users;

class User {
    private users $usersModel;
    public function __construct() { $this->usersModel = new users(); }

    public function isAuthorized(): bool {
        return isset($_SESSION['auth']['user_id']);
    }

    public function findByLogin(string $login): ?array {
        return \Nibiru\Pdo::fetchRow(
            'SELECT * FROM users WHERE user_login = :login',
            [':login' => $login]
        ) ?: null;
    }
}
```
Esto mantiene los controladores ligeros (`$this->user->isAuthorized()`) mientras deja el modelo generado intacto.

## Trucos para múltiples controladores

El adaptador generado `Db` es específico del controlador. Si cambias de MySQL a PostgreSQL, regenera los modelos para que extiendan la clase base correcta:

- MySQL / PDO → `Nibiru\Adapter\MySQL\Db`
- PostgreSQL (libpq) → `Nibiru\Adapter\PostgreSQL\Db`
- ODBC → `Nibiru\Adapter\Odbc\Db`

Mismos ayudantes de consulta, diferente adaptador por debajo.

## Cuando saltarse el generador

Bases de datos de solo lectura, sistemas de proveedores o cualquier esquema que no controle: establezca `database = false`, escriba manualmente clases de modelo mínimas que coincidan con las columnas que realmente utilice y regístrelas.
