> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Modelos pivote personalizados y chaperone

> Cómo tratar la tabla intermedia de belongsToMany como un modelo Pivot personalizado y cómo funciona el eager loading automático con chaperone, añadido en Laravel 13.

## Qué es un modelo pivote personalizado

La tabla intermedia de [belongsToMany (muchos a muchos)](/es/eloquent-relationships#belongsToMany-muchos-a-muchos) se trata por defecto como una instancia sencilla de `Illuminate\Database\Eloquent\Relations\Pivot`. Si quieres añadir columnas adicionales a la tabla intermedia (fecha de aprobación, tipo de rol, etc.) o incluir accessors, mutators o métodos propios, crea un modelo personalizado que herede de `Pivot`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    protected function casts(): array
    {
        return [
            'approved' => 'boolean',
        ];
    }
}
```

En la definición de `belongsToMany`, llama a `using()` para indicarle a la relación que utilice este modelo personalizado.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Role extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)
            ->using(RoleUser::class);
    }
}
```

<Info>
  Al nombrar un modelo pivote personalizado, sigue la convención de usar los nombres **en singular y por orden alfabético** (`RoleUser`, no `UserRole`). Esto es una convención de nombrado; el nombre real de la clase lo eliges libremente.
</Info>

## Especificar los atributos a obtener con `as()`

Por defecto se accede a los valores de la tabla intermedia mediante la propiedad `pivot`. Con el método `as()` puedes cambiar ese nombre.

```php theme={null}
return $this->belongsToMany(Role::class)
    ->using(RoleUser::class)
    ->as('membership')
    ->withTimestamps()
    ->withPivot('approved');
```

```php theme={null}
foreach ($user->roles as $role) {
    echo $role->membership->approved;
    echo $role->membership->created_at;
}
```

## Columnas adicionales y timestamps

Si la tabla intermedia tiene columnas adicionales como `approved`, indícalas explícitamente con `withPivot()` para que se incluyan en el resultado. Si quieres gestionar `created_at` / `updated_at`, llama a `withTimestamps()`.

```php theme={null}
return $this->belongsToMany(Role::class)
    ->using(RoleUser::class)
    ->withPivot('approved')
    ->withTimestamps();
```

<Warning>
  Eloquent solo actualiza automáticamente el `updated_at` de la tabla intermedia cuando ese modelo pivote se ha indicado explícitamente con `using()`. Aunque uses la clase `Pivot` por defecto, `withTimestamps()` sigue funcionando, pero al especificar un modelo personalizado con `using()` podrás aprovechar eventos personalizados, casts propios, etc.
</Warning>

## Referencia inversa desde el modelo pivote

En un modelo pivote personalizado puedes definir libremente relaciones `belongsTo` hacia el modelo declarante y el modelo relacionado.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    public function role(): BelongsTo
    {
        return $this->belongsTo(Role::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}
```

Con esto, incluso obteniendo el modelo pivote por separado, puedes acceder a los modelos relacionados con `$roleUser->role` o `$roleUser->user`. Ahora bien, si quieres que estas relaciones se cargen automáticamente (Eager loading) al ejecutar la consulta padre, puedes usar el método `chaperone()` descrito a continuación.

## Eager loading automático con `chaperone()` (Laravel 13)

En Laravel 13 se ha añadido el método `chaperone()`, que hidrata automáticamente (equivalente al eager loading) las relaciones `belongsTo` como `role()` / `user()` definidas en el modelo pivote cuando se ejecuta la consulta de `belongsToMany`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Role extends Model
{
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)
            ->using(RoleUser::class)
            ->chaperone();
    }
}
```

Al llamar a `chaperone()`, Eloquent infiere automáticamente el nombre de las relaciones `belongsTo` del modelo pivote (`RoleUser`) y, al obtener una colección como `Role::with('users')`, asigna las referencias al modelo declarante y al relacionado sin lanzar consultas adicionales.

```php theme={null}
$role = Role::with('users')->first();

foreach ($role->users as $user) {
    // Acceso al modelo padre a través del pivote, sin consultas adicionales
    echo $user->pivot->role->name;
}
```

### Cuando los nombres de relación no son estándar

Si el nombre del método `belongsTo` en el modelo pivote no sigue la convención estándar (nombre del modelo declarante o relacionado en camelCase singular), indícalo explícitamente en los argumentos de `chaperone()`.

```php theme={null}
return $this->belongsToMany(User::class)
    ->using(RoleUser::class)
    ->chaperone(declaring: 'role', related: 'user');
```

<Tip>
  `chaperone()` resuelve el «problema N+1» también para las referencias vía tabla intermedia. En aplicaciones que consultan con frecuencia información del modelo padre desde el pivote (por ejemplo, mostrar juntos la fecha de aprobación y el nombre del usuario), combínalo con el eager loading habitual mediante `with()` para sacarle el máximo partido.
</Tip>

## Próximos pasos

<Card title="Relaciones" icon="link" href="/es/eloquent-relationships">
  Vuelve a repasar cómo definir las relaciones básicas, incluida belongsToMany.
</Card>

<Card title="Observers de Eloquent y eventos del modelo" icon="bolt" href="/es/advanced/eloquent-observers">
  Aprende a enganchar el guardado y la actualización del modelo pivote mediante eventos del modelo.
</Card>


## Related topics

- [Introducción a las relaciones de Eloquent](/es/eloquent-relationships.md)
- [Guía de actualización de Laravel 12 a 13](/es/blog/upgrade-12-to-13.md)
- [Casts personalizados de Eloquent](/es/advanced/eloquent-casts.md)
- [Implementación de un guard de autenticación personalizado](/es/advanced/custom-auth-guard.md)
- [Modelos](/es/packages/laravel-copilot-sdk/models.md)
