Estamos actualizando el sitio. Durante unos días es posible que veas fallos de diseño o de traducción. La documentación sigue disponible: si una página se ve mal, recárgala más tarde.

Inicio Laravel 10.x Eloquent: Relaciones

Eloquent: Relaciones

10.x 7 de mar. de 2026

#Introducción

Las tablas de base de datos suelen estar relacionadas entre sí. Por ejemplo, una publicación de blog puede tener muchos comentarios o un pedido podría estar relacionado con el usuario que lo realizó. Eloquent facilita la gestión y el trabajo con estas relaciones, y soporta una variedad de relaciones comunes:

#Definiendo Relaciones

Las relaciones de Eloquent se definen como métodos en sus clases de modelos Eloquent. Dado que las relaciones también funcionan como potentes constructores de consultas, definir relaciones como métodos proporciona capacidades avanzadas de encadenamiento y consulta. Por ejemplo, podemos encadenar restricciones adicionales en esta relación posts:

$user->posts()->where('active', 1)->get();

Pero, antes de profundizar en el uso de relaciones, aprendamos cómo definir cada tipo de relación que Eloquent soporta.

#Uno a Uno

Una relación uno a uno es un tipo muy básico de relación en bases de datos. Por ejemplo, un modelo User podría estar asociado con un solo modelo Phone. Para definir esta relación, colocaremos un método phone en el modelo User. El método phone debe llamar al método hasOne y devolver su resultado. El método hasOne está disponible para su modelo a través de la clase base Illuminate\Database\Eloquent\Model:

<?php

namespace App\Models;

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

class User extends Model
{
    /**
     * Obtener el teléfono asociado con el usuario.
     */
    public function phone(): HasOne
    {
        return $this->hasOne(Phone::class);
    }
}

El primer argumento pasado al método hasOne es el nombre de la clase del modelo relacionado. Una vez definida la relación, podemos recuperar el registro relacionado usando las propiedades dinámicas de Eloquent. Las propiedades dinámicas permiten acceder a los métodos de relación como si fueran propiedades definidas en el modelo:

$phone = User::find(1)->phone;

Eloquent determina la clave foránea de la relación basándose en el nombre del modelo padre. En este caso, se asume automáticamente que el modelo Phone tiene una clave foránea user_id. Si desea sobrescribir esta convención, puede pasar un segundo argumento al método hasOne:

return $this->hasOne(Phone::class, 'foreign_key');

Además, Eloquent asume que la clave foránea debe tener un valor que coincida con la columna de clave primaria del padre. En otras palabras, Eloquent buscará el valor de la columna id del usuario en la columna user_id del registro Phone. Si desea que la relación use un valor de clave primaria distinto a id o a la propiedad $primaryKey de su modelo, puede pasar un tercer argumento al método hasOne:

return $this->hasOne(Phone::class, 'foreign_key', 'local_key');

#Definiendo el Inverso de la Relación

Así que podemos acceder al modelo Phone desde nuestro modelo User. A continuación, definamos una relación en el modelo Phone que nos permita acceder al usuario que posee el teléfono. Podemos definir el inverso de una relación hasOne usando el método belongsTo:

<?php

namespace App\Models;

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

class Phone extends Model
{
    /**
     * Obtener el usuario que posee el teléfono.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

Al invocar el método user, Eloquent intentará encontrar un modelo User que tenga un id que coincida con la columna user_id en el modelo Phone.

Eloquent determina el nombre de la clave foránea examinando el nombre del método de relación y añadiendo el sufijo _id. Por lo tanto, en este caso, Eloquent asume que el modelo Phone tiene una columna user_id. Sin embargo, si la clave foránea en el modelo Phone no es user_id, puede pasar un nombre de clave personalizado como segundo argumento al método belongsTo:

/**
 * Obtener el usuario que posee el teléfono.
 */
public function user(): BelongsTo
{
    return $this->belongsTo(User::class, 'foreign_key');
}

Si el modelo padre no usa id como clave primaria, o desea encontrar el modelo asociado usando una columna diferente, puede pasar un tercer argumento al método belongsTo especificando la clave personalizada de la tabla padre:

/**
 * Obtener el usuario que posee el teléfono.
 */
public function user(): BelongsTo
{
    return $this->belongsTo(User::class, 'foreign_key', 'owner_key');
}

#Uno a Muchos

Una relación uno a muchos se usa para definir relaciones donde un solo modelo es el padre de uno o más modelos hijos. Por ejemplo, una publicación de blog puede tener un número infinito de comentarios. Como todas las demás relaciones de Eloquent, las relaciones uno a muchos se definen mediante un método en su modelo Eloquent:

<?php

namespace App\Models;

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

class Post extends Model
{
    /**
     * Obtener los comentarios para la publicación del blog.
     */
    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}

Recuerde, Eloquent determinará automáticamente la columna de clave foránea adecuada para el modelo Comment. Por convención, Eloquent tomará el nombre del modelo padre en "snake case" y le añadirá el sufijo _id. Así, en este ejemplo, Eloquent asumirá que la columna de clave foránea en el modelo Comment es post_id.

Una vez definido el método de relación, podemos acceder a la colección de comentarios relacionados accediendo a la propiedad comments. Recuerde que, dado que Eloquent proporciona "propiedades dinámicas de relación", podemos acceder a los métodos de relación como si fueran propiedades definidas en el modelo:

use App\Models\Post;

$comments = Post::find(1)->comments;

foreach ($comments as $comment) {
    // ...
}

Dado que todas las relaciones también funcionan como constructores de consultas, puede añadir restricciones adicionales a la consulta de la relación llamando al método comments y encadenando condiciones a la consulta:

$comment = Post::find(1)->comments()
                    ->where('title', 'foo')
                    ->first();

Al igual que el método hasOne, también puede sobrescribir las claves foráneas y locales pasando argumentos adicionales al método hasMany:

return $this->hasMany(Comment::class, 'foreign_key');

return $this->hasMany(Comment::class, 'foreign_key', 'local_key');

#Uno a Muchos (Inverso) / Pertenece a

Ahora que podemos acceder a todos los comentarios de una publicación, definamos una relación que permita a un comentario acceder a su publicación padre. Para definir el inverso de una relación hasMany, defina un método de relación en el modelo hijo que llame al método belongsTo:

<?php

namespace App\Models;

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

class Comment extends Model
{
    /**
     * Obtener la publicación que posee el comentario.
     */
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}

Una vez definida la relación, podemos recuperar la publicación padre de un comentario accediendo a la "propiedad dinámica de relación" post:

use App\Models\Comment;

$comment = Comment::find(1);

return $comment->post->title;

En el ejemplo anterior, Eloquent intentará encontrar un modelo Post que tenga un id que coincida con la columna post_id en el modelo Comment.

Eloquent determina el nombre predeterminado de la clave foránea examinando el nombre del método de relación y añadiendo un guion bajo _ seguido del nombre de la columna de clave primaria del modelo padre. Así, en este ejemplo, Eloquent asumirá que la clave foránea del modelo Post en la tabla comments es post_id.

Sin embargo, si la clave foránea para su relación no sigue estas convenciones, puede pasar un nombre de clave foránea personalizado como segundo argumento al método belongsTo:

/**
 * Obtener la publicación que posee el comentario.
 */
public function post(): BelongsTo
{
    return $this->belongsTo(Post::class, 'foreign_key');
}

Si su modelo padre no usa id como clave primaria, o desea encontrar el modelo asociado usando una columna diferente, puede pasar un tercer argumento al método belongsTo especificando la clave personalizada de la tabla padre:

/**
 * Obtener la publicación que posee el comentario.
 */
public function post(): BelongsTo
{
    return $this->belongsTo(Post::class, 'foreign_key', 'owner_key');
}

#Modelos Predeterminados

Las relaciones belongsTo, hasOne, hasOneThrough y morphOne le permiten definir un modelo predeterminado que será devuelto si la relación dada es null. Este patrón se conoce comúnmente como el patrón Null Object y puede ayudar a eliminar verificaciones condicionales en su código. En el siguiente ejemplo, la relación user devolverá un modelo vacío App\Models\User si no hay un usuario asociado al modelo Post:

/**
 * Obtener el autor de la publicación.
 */
public function user(): BelongsTo
{
    return $this->belongsTo(User::class)->withDefault();
}

Para poblar el modelo predeterminado con atributos, puede pasar un array o una closure al método withDefault:

/**
 * Obtener el autor de la publicación.
 */
public function user(): BelongsTo
{
    return $this->belongsTo(User::class)->withDefault([
        'name' => 'Guest Author',
    ]);
}

/**
 * Obtener el autor de la publicación.
 */
public function user(): BelongsTo
{
    return $this->belongsTo(User::class)->withDefault(function (User $user, Post $post) {
        $user->name = 'Guest Author';
    });
}

#Consultando Relaciones Belongs To

Al consultar los hijos de una relación "belongs to", puede construir manualmente la cláusula where para recuperar los modelos Eloquent correspondientes:

use App\Models\Post;

$posts = Post::where('user_id', $user->id)->get();

Sin embargo, puede resultar más conveniente usar el método whereBelongsTo, que determinará automáticamente la relación y la clave foránea adecuadas para el modelo dado:

$posts = Post::whereBelongsTo($user)->get();

También puede proporcionar una instancia de colección al método whereBelongsTo. Al hacerlo, Laravel recuperará modelos que pertenezcan a cualquiera de los modelos padres dentro de la colección:

$users = User::where('vip', true)->get();

$posts = Post::whereBelongsTo($users)->get();

Por defecto, Laravel determinará la relación asociada con el modelo dado basándose en el nombre de la clase del modelo; sin embargo, puede especificar manualmente el nombre de la relación proporcionándolo como segundo argumento al método whereBelongsTo:

$posts = Post::whereBelongsTo($user, 'author')->get();

#Tiene Uno de Muchos

A veces un modelo puede tener muchos modelos relacionados, pero usted quiere recuperar fácilmente el modelo relacionado "más reciente" o "más antiguo" de la relación. Por ejemplo, un modelo User puede estar relacionado con muchos modelos Order, pero desea definir una forma conveniente de interactuar con el pedido más reciente que el usuario ha realizado. Puede lograr esto usando el tipo de relación hasOne combinado con los métodos ofMany:

/**
 * Obtener el pedido más reciente del usuario.
 */
public function latestOrder(): HasOne
{
    return $this->hasOne(Order::class)->latestOfMany();
}

De igual manera, puede definir un método para recuperar el modelo relacionado "más antiguo" o primero de una relación:

/**
 * Obtener el pedido más antiguo del usuario.
 */
public function oldestOrder(): HasOne
{
    return $this->hasOne(Order::class)->oldestOfMany();
}

Por defecto, los métodos latestOfMany y oldestOfMany recuperarán el modelo relacionado más reciente o más antiguo basándose en la clave primaria del modelo, que debe ser ordenable. Sin embargo, a veces puede querer recuperar un solo modelo de una relación más grande usando un criterio de ordenación diferente.

Por ejemplo, usando el método ofMany, puede recuperar el pedido más caro del usuario. El método ofMany acepta la columna ordenable como primer argumento y qué función agregada (min o max) aplicar al consultar el modelo relacionado:

/**
 * Obtener el pedido más grande del usuario.
 */
public function largestOrder(): HasOne
{
    return $this->hasOne(Order::class)->ofMany('price', 'max');
}
Внимание

Debido a que PostgreSQL no soporta ejecutar la función MAX sobre columnas UUID, actualmente no es posible usar relaciones uno-de-muchos en combinación con columnas UUID en PostgreSQL.

#Convirtiendo Relaciones "Muchos" a Relaciones "Uno"

A menudo, al recuperar un solo modelo usando los métodos latestOfMany, oldestOfMany o ofMany, ya tiene definida una relación "has many" para el mismo modelo. Para mayor comodidad, Laravel le permite convertir fácilmente esta relación en una relación "has one" invocando el método one en la relación:

/**
 * Obtener los pedidos del usuario.
 */
public function orders(): HasMany
{
    return $this->hasMany(Order::class);
}

/**
 * Obtener el pedido más grande del usuario.
 */
public function largestOrder(): HasOne
{
    return $this->orders()->one()->ofMany('price', 'max');
}

#Relaciones Avanzadas Has One of Many

Es posible construir relaciones más avanzadas "has one of many". Por ejemplo, un modelo Product puede tener muchos modelos Price asociados que se mantienen en el sistema incluso después de que se publique un nuevo precio. Además, los datos de precios nuevos para el producto pueden publicarse con anticipación para que entren en vigor en una fecha futura mediante una columna published_at.

En resumen, necesitamos recuperar el precio publicado más reciente donde la fecha de publicación no esté en el futuro. Además, si dos precios tienen la misma fecha de publicación, preferiremos el precio con el ID más alto. Para lograr esto, debemos pasar un array al método ofMany que contenga las columnas ordenables que determinan el precio más reciente. Además, se proporcionará una closure como segundo argumento al método ofMany. Esta closure será responsable de agregar restricciones adicionales de fecha de publicación a la consulta de la relación:

/**
 * Obtener el precio actual del producto.
 */
public function currentPricing(): HasOne
{
    return $this->hasOne(Price::class)->ofMany([
        'published_at' => 'max',
        'id' => 'max',
    ], function (Builder $query) {
        $query->where('published_at', '<', now());
    });
}

#Tiene Uno a Través

La relación "has-one-through" define una relación uno a uno con otro modelo. Sin embargo, esta relación indica que el modelo declarativo puede estar relacionado con una instancia de otro modelo a través de un tercer modelo.

Por ejemplo, en una aplicación de taller de reparación de vehículos, cada modelo Mechanic puede estar asociado con un modelo Car, y cada modelo Car puede estar asociado con un modelo Owner. Aunque el mecánico y el propietario no tienen una relación directa en la base de datos, el mecánico puede acceder al propietario a través del modelo Car. Veamos las tablas necesarias para definir esta relación:

mechanics
    id - integer
    name - string

cars
    id - integer
    model - string
    mechanic_id - integer

owners
    id - integer
    name - string
    car_id - integer

Ahora que hemos examinado la estructura de las tablas para la relación, definamos la relación en el modelo Mechanic:

<?php

namespace App\Models;

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

class Mechanic extends Model
{
    /**
     * Obtener el propietario del coche.
     */
    public function carOwner(): HasOneThrough
    {
        return $this->hasOneThrough(Owner::class, Car::class);
    }
}

El primer argumento pasado al método hasOneThrough es el nombre del modelo final al que deseamos acceder, mientras que el segundo argumento es el nombre del modelo intermedio.

O, si las relaciones relevantes ya han sido definidas en todos los modelos involucrados en la relación, puede definir de forma fluida una relación "has-one-through" invocando el método through y suministrando los nombres de esas relaciones. Por ejemplo, si el modelo Mechanic tiene una relación cars y el modelo Car tiene una relación owner, puede definir una relación "has-one-through" que conecte al mecánico y al propietario así:

// Sintaxis basada en cadenas...
return $this->through('cars')->has('owner');

// Sintaxis dinámica...
return $this->throughCars()->hasOwner();

#Convenciones de Claves

Se usarán las convenciones típicas de claves foráneas de Eloquent al realizar las consultas de la relación. Si desea personalizar las claves de la relación, puede pasarlas como tercer y cuarto argumento al método hasOneThrough. El tercer argumento es el nombre de la clave foránea en el modelo intermedio. El cuarto argumento es el nombre de la clave foránea en el modelo final. El quinto argumento es la clave local, mientras que el sexto argumento es la clave local del modelo intermedio:

class Mechanic extends Model
{
    /**
     * Obtener el propietario del coche.
     */
    public function carOwner(): HasOneThrough
    {
        return $this->hasOneThrough(
            Owner::class,
            Car::class,
            'mechanic_id', // Clave foránea en la tabla cars...
            'car_id', // Clave foránea en la tabla owners...
            'id', // Clave local en la tabla mechanics...
            'id' // Clave local en la tabla cars...
        );
    }
}

O, como se mencionó anteriormente, si las relaciones relevantes ya han sido definidas en todos los modelos involucrados en la relación, puede definir de forma fluida una relación "has-one-through" invocando el método through y suministrando los nombres de esas relaciones. Este enfoque ofrece la ventaja de reutilizar las convenciones de claves ya definidas en las relaciones existentes:

// Sintaxis basada en cadenas...
return $this->through('cars')->has('owner');

// Sintaxis dinámica...
return $this->throughCars()->hasOwner();

#Tiene Muchos a Través

La relación "has-many-through" proporciona una forma conveniente de acceder a relaciones distantes a través de una relación intermedia. Por ejemplo, supongamos que estamos construyendo una plataforma de despliegue como Laravel Vapor. Un modelo Project podría acceder a muchos modelos Deployment a través de un modelo intermedio Environment. Usando este ejemplo, podría reunir fácilmente todos los despliegues para un proyecto dado. Veamos las tablas necesarias para definir esta relación:

projects
    id - integer
    name - string

environments
    id - integer
    project_id - integer
    name - string

deployments
    id - integer
    environment_id - integer
    commit_hash - string

Ahora que hemos examinado la estructura de las tablas para la relación, definamos la relación en el modelo Project:

<?php

namespace App\Models;

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

class Project extends Model
{
    /**
     * Obtener todos los despliegues para el proyecto.
     */
    public function deployments(): HasManyThrough
    {
        return $this->hasManyThrough(Deployment::class, Environment::class);
    }
}

El primer argumento pasado al método hasManyThrough es el nombre del modelo final al que deseamos acceder, mientras que el segundo argumento es el nombre del modelo intermedio.

O, si las relaciones relevantes ya han sido definidas en todos los modelos involucrados en la relación, puede definir de forma fluida una relación "has-many-through" invocando el método through y suministrando los nombres de esas relaciones. Por ejemplo, si el modelo Project tiene una relación environments y el modelo Environment tiene una relación deployments, puede definir una relación "has-many-through" que conecte el proyecto y los despliegues así:

// Sintaxis basada en cadenas...
return $this->through('environments')->has('deployments');

// Sintaxis dinámica...
return $this->throughEnvironments()->hasDeployments();

Aunque la tabla del modelo Deployment no contiene una columna project_id, la relación hasManyThrough proporciona acceso a los despliegues de un proyecto mediante $project->deployments. Para recuperar estos modelos, Eloquent inspecciona la columna project_id en la tabla del modelo intermedio Environment. Después de encontrar los IDs de los entornos relevantes, se usan para consultar la tabla del modelo Deployment.

#Convenciones de Claves

Se utilizarán las convenciones típicas de claves foráneas de Eloquent al realizar las consultas de la relación. Si desea personalizar las claves de la relación, puede pasarlas como el tercer y cuarto argumento al método hasManyThrough. El tercer argumento es el nombre de la clave foránea en el modelo intermedio. El cuarto argumento es el nombre de la clave foránea en el modelo final. El quinto argumento es la clave local, mientras que el sexto argumento es la clave local del modelo intermedio:

class Project extends Model
{
    public function deployments(): HasManyThrough
    {
        return $this->hasManyThrough(
            Deployment::class,
            Environment::class,
            'project_id', // Clave foránea en la tabla environments...
            'environment_id', // Clave foránea en la tabla deployments...
            'id', // Clave local en la tabla projects...
            'id' // Clave local en la tabla environments...
        );
    }
}

O, como se mencionó anteriormente, si las relaciones relevantes ya han sido definidas en todos los modelos involucrados en la relación, puede definir de forma fluida una relación "has-many-through" invocando el método through y suministrando los nombres de esas relaciones. Este enfoque ofrece la ventaja de reutilizar las convenciones de claves ya definidas en las relaciones existentes:

// Sintaxis basada en cadenas...
return $this->through('environments')->has('deployments');

// Sintaxis dinámica...
return $this->throughEnvironments()->hasDeployments();

#Relaciones Muchos a Muchos

Las relaciones muchos a muchos son un poco más complejas que las relaciones hasOne y hasMany. Un ejemplo de una relación muchos a muchos es un usuario que tiene muchos roles y esos roles también son compartidos por otros usuarios en la aplicación. Por ejemplo, un usuario puede tener asignados los roles de "Author" y "Editor"; sin embargo, esos roles también pueden ser asignados a otros usuarios. Por lo tanto, un usuario tiene muchos roles y un rol tiene muchos usuarios.

#Estructura de la Tabla

Para definir esta relación, se necesitan tres tablas en la base de datos: users, roles y role_user. La tabla role_user se deriva del orden alfabético de los nombres de los modelos relacionados y contiene las columnas user_id y role_id. Esta tabla se usa como tabla intermedia que enlaza usuarios y roles.

Recuerde que, dado que un rol puede pertenecer a muchos usuarios, no podemos simplemente colocar una columna user_id en la tabla roles. Esto significaría que un rol solo podría pertenecer a un único usuario. Para soportar que los roles sean asignados a múltiples usuarios, se necesita la tabla role_user. Podemos resumir la estructura de las tablas de la relación así:

users
    id - integer
    name - string

roles
    id - integer
    name - string

role_user
    user_id - integer
    role_id - integer

#Estructura del Modelo

Las relaciones muchos a muchos se definen escribiendo un método que devuelve el resultado del método belongsToMany. El método belongsToMany es proporcionado por la clase base Illuminate\Database\Eloquent\Model que usan todos los modelos Eloquent de su aplicación. Por ejemplo, definamos un método roles en nuestro modelo User. El primer argumento que se pasa a este método es el nombre de la clase del modelo relacionado:

<?php

namespace App\Models;

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

class User extends Model
{
    /**
     * Los roles que pertenecen al usuario.
     */
    public function roles(): BelongsToMany
    {
        return $this->belongsToMany(Role::class);
    }
}

Una vez definida la relación, puede acceder a los roles del usuario usando la propiedad dinámica de relación roles:

use App\Models\User;

$user = User::find(1);

foreach ($user->roles as $role) {
    // ...
}

Dado que todas las relaciones también funcionan como constructores de consultas, puede agregar más restricciones a la consulta de la relación llamando al método roles y encadenando condiciones a la consulta:

$roles = User::find(1)->roles()->orderBy('name')->get();

Para determinar el nombre de la tabla intermedia de la relación, Eloquent unirá los dos nombres de los modelos relacionados en orden alfabético. Sin embargo, usted es libre de sobrescribir esta convención. Puede hacerlo pasando un segundo argumento al método belongsToMany:

return $this->belongsToMany(Role::class, 'role_user');

Además de personalizar el nombre de la tabla intermedia, también puede personalizar los nombres de las columnas de las claves en la tabla pasando argumentos adicionales al método belongsToMany. El tercer argumento es el nombre de la clave foránea del modelo en el que está definiendo la relación, mientras que el cuarto argumento es el nombre de la clave foránea del modelo al que se está uniendo:

return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');

#Definiendo el Inverso de la Relación

Para definir el "inverso" de una relación muchos a muchos, debe definir un método en el modelo relacionado que también devuelva el resultado del método belongsToMany. Para completar nuestro ejemplo de usuario / rol, definamos el método users en el modelo Role:

<?php

namespace App\Models;

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

class Role extends Model
{
    /**
     * Los usuarios que pertenecen al rol.
     */
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class);
    }
}

Como puede ver, la relación se define exactamente igual que su contraparte en el modelo User, con la excepción de que referencia al modelo App\Models\User. Dado que reutilizamos el método belongsToMany, todas las opciones habituales de personalización de tablas y claves están disponibles al definir el "inverso" de las relaciones muchos a muchos.

#Recuperando Columnas de la Tabla Intermedia

Como ya ha aprendido, trabajar con relaciones muchos a muchos requiere la presencia de una tabla intermedia. Eloquent proporciona formas muy útiles de interactuar con esta tabla. Por ejemplo, supongamos que nuestro modelo User tiene muchos modelos Role relacionados. Después de acceder a esta relación, podemos acceder a la tabla intermedia usando el atributo pivot en los modelos:

use App\Models\User;

$user = User::find(1);

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}

Observe que a cada modelo Role que recuperamos se le asigna automáticamente un atributo pivot. Este atributo contiene un modelo que representa la tabla intermedia.

Por defecto, solo las claves del modelo estarán presentes en el modelo pivot. Si su tabla intermedia contiene atributos adicionales, debe especificarlos al definir la relación:

return $this->belongsToMany(Role::class)->withPivot('active', 'created_by');

Si desea que su tabla intermedia tenga las marcas de tiempo created_at y updated_at que son mantenidas automáticamente por Eloquent, llame al método withTimestamps al definir la relación:

return $this->belongsToMany(Role::class)->withTimestamps();
Внимание

Las tablas intermedias que utilizan las marcas de tiempo mantenidas automáticamente por Eloquent deben tener ambas columnas de marca de tiempo created_at y updated_at.

#Personalizando el Nombre del Atributo pivot

Como se mencionó anteriormente, los atributos de la tabla intermedia pueden ser accedidos en los modelos a través del atributo pivot. Sin embargo, usted es libre de personalizar el nombre de este atributo para reflejar mejor su propósito dentro de su aplicación.

Por ejemplo, si su aplicación contiene usuarios que pueden suscribirse a podcasts, probablemente tenga una relación muchos a muchos entre usuarios y podcasts. En este caso, puede que desee renombrar el atributo de la tabla intermedia a subscription en lugar de pivot. Esto se puede hacer usando el método as al definir la relación:

return $this->belongsToMany(Podcast::class)
                ->as('subscription')
                ->withTimestamps();

Una vez que se ha especificado el nombre personalizado del atributo de la tabla intermedia, puede acceder a los datos de la tabla intermedia usando el nombre personalizado:

$users = User::with('podcasts')->get();

foreach ($users->flatMap->podcasts as $podcast) {
    echo $podcast->subscription->created_at;
}

#Filtrando Consultas mediante Columnas de la Tabla Intermedia

También puede filtrar los resultados devueltos por las consultas de relaciones belongsToMany usando los métodos wherePivot, wherePivotIn, wherePivotNotIn, wherePivotBetween, wherePivotNotBetween, wherePivotNull y wherePivotNotNull al definir la relación:

return $this->belongsToMany(Role::class)
                ->wherePivot('approved', 1);

return $this->belongsToMany(Role::class)
                ->wherePivotIn('priority', [1, 2]);

return $this->belongsToMany(Role::class)
                ->wherePivotNotIn('priority', [1, 2]);

return $this->belongsToMany(Podcast::class)
                ->as('subscriptions')
                ->wherePivotBetween('created_at', ['2020-01-01 00:00:00', '2020-12-31 00:00:00']);

return $this->belongsToMany(Podcast::class)
                ->as('subscriptions')
                ->wherePivotNotBetween('created_at', ['2020-01-01 00:00:00', '2020-12-31 00:00:00']);

return $this->belongsToMany(Podcast::class)
                ->as('subscriptions')
                ->wherePivotNull('expired_at');

return $this->belongsToMany(Podcast::class)
                ->as('subscriptions')
                ->wherePivotNotNull('expired_at');

#Ordenando Consultas mediante Columnas de la Tabla Intermedia

Puede ordenar los resultados devueltos por las consultas de relaciones belongsToMany usando el método orderByPivot. En el siguiente ejemplo, recuperaremos todas las insignias más recientes para el usuario:

return $this->belongsToMany(Badge::class)
                ->where('rank', 'gold')
                ->orderByPivot('created_at', 'desc');

#Definiendo Modelos Personalizados para la Tabla Intermedia

Si desea definir un modelo personalizado para representar la tabla intermedia de su relación muchos a muchos, puede llamar al método using al definir la relación. Los modelos pivot personalizados le brindan la oportunidad de definir comportamientos adicionales en el modelo pivot, como métodos y casts.

Los modelos pivot personalizados muchos a muchos deben extender la clase Illuminate\Database\Eloquent\Relations\Pivot, mientras que los modelos pivot personalizados polimórficos muchos a muchos deben extender la clase Illuminate\Database\Eloquent\Relations\MorphPivot. Por ejemplo, podemos definir un modelo Role que use un modelo pivot personalizado RoleUser:

<?php

namespace App\Models;

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

class Role extends Model
{
    /**
     * Los usuarios que pertenecen al rol.
     */
    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class)->using(RoleUser::class);
    }
}

Al definir el modelo RoleUser, debe extender la clase Illuminate\Database\Eloquent\Relations\Pivot:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    // ...
}
Внимание

Los modelos pivot no pueden usar el trait SoftDeletes. Si necesita eliminar suavemente registros pivot, considere convertir su modelo pivot en un modelo Eloquent real.

#Modelos Pivot Personalizados y IDs Auto-incrementales

Si ha definido una relación muchos a muchos que usa un modelo pivot personalizado, y ese modelo pivot tiene una clave primaria auto-incremental, debe asegurarse de que su clase de modelo pivot personalizada defina una propiedad incrementing establecida en true.

/**
 * Indica si los IDs son auto-incrementales.
 *
 * @var bool
 */
public $incrementing = true;

#Relaciones Polimórficas

Una relación polimórfica permite que el modelo hijo pertenezca a más de un tipo de modelo usando una sola asociación. Por ejemplo, imagine que está construyendo una aplicación que permite a los usuarios compartir publicaciones de blog y videos. En tal aplicación, un modelo Comment podría pertenecer tanto a los modelos Post como Video.

#Uno a Uno (Polimórfico)

#Estructura de la Tabla

Una relación polimórfica uno a uno es similar a una relación uno a uno típica; sin embargo, el modelo hijo puede pertenecer a más de un tipo de modelo usando una sola asociación. Por ejemplo, un Post de blog y un User pueden compartir una relación polimórfica con un modelo Image. Usar una relación polimórfica uno a uno le permite tener una sola tabla de imágenes únicas que pueden estar asociadas con posts y usuarios. Primero, examinemos la estructura de la tabla:

posts
    id - integer
    name - string

users
    id - integer
    name - string

images
    id - integer
    url - string
    imageable_id - integer
    imageable_type - string

Observe las columnas imageable_id y imageable_type en la tabla images. La columna imageable_id contendrá el valor ID del post o usuario, mientras que la columna imageable_type contendrá el nombre de la clase del modelo padre. La columna imageable_type es usada por Eloquent para determinar qué "tipo" de modelo padre devolver al acceder a la relación imageable. En este caso, la columna contendrá App\Models\Post o App\Models\User.

#Estructura del Modelo

A continuación, examinemos las definiciones de los modelos necesarias para construir esta relación:

<?php

namespace App\Models;

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

class Image extends Model
{
    /**
     * Obtener el modelo padre imageable (usuario o post).
     */
    public function imageable(): MorphTo
    {
        return $this->morphTo();
    }
}

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

class Post extends Model
{
    /**
     * Obtener la imagen del post.
     */
    public function image(): MorphOne
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

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

class User extends Model
{
    /**
     * Obtener la imagen del usuario.
     */
    public function image(): MorphOne
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

#Recuperando la Relación

Una vez que su tabla de base de datos y modelos estén definidos, puede acceder a las relaciones a través de sus modelos. Por ejemplo, para recuperar la imagen de un post, podemos acceder a la propiedad dinámica de relación image:

use App\Models\Post;

$post = Post::find(1);

$image = $post->image;

Puede recuperar el padre del modelo polimórfico accediendo al nombre del método que realiza la llamada a morphTo. En este caso, ese es el método imageable en el modelo Image. Por lo tanto, accederemos a ese método como una propiedad dinámica de relación:

use App\Models\Image;

$image = Image::find(1);

$imageable = $image->imageable;

La relación imageable en el modelo Image devolverá una instancia de Post o User, dependiendo de qué tipo de modelo sea el propietario de la imagen.

#Convenciones de Claves

Si es necesario, puede especificar el nombre de las columnas "id" y "type" utilizadas por su modelo hijo polimórfico. Si lo hace, asegúrese de siempre pasar el nombre de la relación como primer argumento al método morphTo. Normalmente, este valor debe coincidir con el nombre del método, por lo que puede usar la constante __FUNCTION__ de PHP:

/**
 * Obtener el modelo al que pertenece la imagen.
 */
public function imageable(): MorphTo
{
    return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
}

#Uno a Muchos (Polimórfico)

#Estructura de la Tabla

Una relación polimórfica uno a muchos es similar a una relación uno a muchos típica; sin embargo, el modelo hijo puede pertenecer a más de un tipo de modelo usando una sola asociación. Por ejemplo, imagine que los usuarios de su aplicación pueden "comentar" en posts y videos. Usando relaciones polimórficas, puede usar una sola tabla comments para contener comentarios tanto para posts como para videos. Primero, examinemos la estructura de la tabla requerida para construir esta relación:

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

#Estructura del Modelo

A continuación, examinemos las definiciones de los modelos necesarias para construir esta relación:

<?php

namespace App\Models;

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

class Comment extends Model
{
    /**
     * Obtener el modelo padre commentable (post o video).
     */
    public function commentable(): MorphTo
    {
        return $this->morphTo();
    }
}

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

class Post extends Model
{
    /**
     * Obtener todos los comentarios del post.
     */
    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

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

class Video extends Model
{
    /**
     * Obtener todos los comentarios del video.
     */
    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }
}

#Recuperando la Relación

Una vez que su tabla de base de datos y modelos estén definidos, puede acceder a las relaciones a través de las propiedades dinámicas de relación de su modelo. Por ejemplo, para acceder a todos los comentarios de un post, podemos usar la propiedad dinámica comments:

use App\Models\Post;

$post = Post::find(1);

foreach ($post->comments as $comment) {
    // ...
}

También puede recuperar el padre de un modelo hijo polimórfico accediendo al nombre del método que realiza la llamada a morphTo. En este caso, ese es el método commentable en el modelo Comment. Por lo tanto, accederemos a ese método como una propiedad dinámica de relación para acceder al modelo padre del comentario:

use App\Models\Comment;

$comment = Comment::find(1);

$commentable = $comment->commentable;

La relación commentable en el modelo Comment devolverá una instancia de Post o Video, dependiendo de qué tipo de modelo sea el padre del comentario.

#Uno de Muchos (Polimórfico)

A veces un modelo puede tener muchos modelos relacionados, pero usted quiere recuperar fácilmente el modelo relacionado "más reciente" o "más antiguo" de la relación. Por ejemplo, un modelo User puede estar relacionado con muchos modelos Image, pero usted quiere definir una forma conveniente de interactuar con la imagen más reciente que el usuario ha subido. Puede lograr esto usando el tipo de relación morphOne combinado con los métodos ofMany:

/**
 * Obtener la imagen más reciente del usuario.
 */
public function latestImage(): MorphOne
{
    return $this->morphOne(Image::class, 'imageable')->latestOfMany();
}

De igual manera, puede definir un método para recuperar el modelo relacionado "más antiguo" o primero de una relación:

/**
 * Obtener la imagen más antigua del usuario.
 */
public function oldestImage(): MorphOne
{
    return $this->morphOne(Image::class, 'imageable')->oldestOfMany();
}

Por defecto, los métodos latestOfMany y oldestOfMany recuperarán el modelo relacionado más reciente o más antiguo basado en la clave primaria del modelo, que debe ser ordenable. Sin embargo, a veces puede querer recuperar un solo modelo de una relación más grande usando un criterio de ordenación diferente.

Por ejemplo, usando el método ofMany, puede recuperar la imagen más "gustada" del usuario. El método ofMany acepta la columna ordenable como su primer argumento y qué función agregada (min o max) aplicar al consultar el modelo relacionado:

/**
 * Obtener la imagen más popular del usuario.
 */
public function bestImage(): MorphOne
{
    return $this->morphOne(Image::class, 'imageable')->ofMany('likes', 'max');
}
Примечание

Es posible construir relaciones "uno de muchos" más avanzadas. Para más información, consulte la documentación de has one of many.

#Muchos a Muchos (Polimórfico)

#Estructura de la Tabla

Las relaciones polimórficas muchos a muchos son un poco más complejas que las relaciones "morph one" y "morph many". Por ejemplo, un modelo Post y un modelo Video podrían compartir una relación polimórfica con un modelo Tag. Usar una relación polimórfica muchos a muchos en esta situación permitiría que su aplicación tenga una sola tabla de etiquetas únicas que pueden estar asociadas con posts o videos. Primero, examinemos la estructura de la tabla requerida para construir esta relación:

posts
    id - integer
    name - string

videos
    id - integer
    name - string

tags
    id - integer
    name - string

taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string
Примечание

Antes de profundizar en las relaciones polimórficas muchos a muchos, puede beneficiarse de leer la documentación sobre relaciones típicas muchos a muchos.

#Estructura del Modelo

Ahora estamos listos para definir las relaciones en los modelos. Los modelos Post y Video contendrán un método tags que llama al método morphToMany proporcionado por la clase base del modelo Eloquent.

El método morphToMany acepta el nombre del modelo relacionado así como el "nombre de la relación". Basándonos en el nombre que asignamos a nuestra tabla intermedia y las claves que contiene, nos referiremos a la relación como "taggable":

<?php

namespace App\Models;

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

class Post extends Model
{
    /**
     * Obtener todas las etiquetas del post.
     */
    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

#Definiendo el Inverso de la Relación

Luego, en el modelo Tag, debe definir un método para cada uno de sus posibles modelos padre. Así, en este ejemplo, definiremos un método posts y un método videos. Ambos métodos deben devolver el resultado del método morphedByMany.

El método morphedByMany acepta el nombre del modelo relacionado así como el "nombre de la relación". Basándonos en el nombre que asignamos a nuestra tabla intermedia y las claves que contiene, nos referiremos a la relación como "taggable":

<?php

namespace App\Models;

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

class Tag extends Model
{
    /**
     * Obtener todos los posts que tienen esta etiqueta asignada.
     */
    public function posts(): MorphToMany
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }

    /**
     * Obtener todos los videos que tienen esta etiqueta asignada.
     */
    public function videos(): MorphToMany
    {
        return $this->morphedByMany(Video::class, 'taggable');
    }
}

#Recuperando la Relación

Una vez que su tabla de base de datos y modelos estén definidos, puede acceder a las relaciones a través de sus modelos. Por ejemplo, para acceder a todas las etiquetas de un post, puede usar la propiedad dinámica de relación tags:

use App\Models\Post;

$post = Post::find(1);

foreach ($post->tags as $tag) {
    // ...
}

Puede obtener el padre de una relación polimórfica desde el modelo hijo polimórfico accediendo al nombre del método que realiza la llamada a morphedByMany. En este caso, esos son los métodos posts o videos en el modelo Tag:

use App\Models\Tag;

$tag = Tag::find(1);

foreach ($tag->posts as $post) {
    // ...
}

foreach ($tag->videos as $video) {
    // ...
}

#Tipos Polimórficos Personalizados

Por defecto, Laravel usará el nombre de clase completamente calificado para almacenar el "tipo" del modelo relacionado. Por ejemplo, dado el ejemplo de relación uno a muchos arriba donde un modelo Comment puede pertenecer a un modelo Post o Video, el valor por defecto de commentable_type sería App\Models\Post o App\Models\Video, respectivamente. Sin embargo, puede que desee desacoplar estos valores de la estructura interna de su aplicación.

Por ejemplo, en lugar de usar los nombres de los modelos como el "tipo", podemos usar cadenas simples como post y video. Al hacerlo, los valores de la columna "tipo" polimórfica en nuestra base de datos seguirán siendo válidos incluso si los modelos son renombrados:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::enforceMorphMap([
    'post' => 'App\Models\Post',
    'video' => 'App\Models\Video',
]);

Puede llamar al método enforceMorphMap en el método boot de su clase App\Providers\AppServiceProvider o crear un proveedor de servicios separado si lo desea.

Puede determinar el alias morph de un modelo dado en tiempo de ejecución usando el método getMorphClass del modelo. Por otro lado, puede determinar el nombre de clase completamente calificado asociado con un alias morph usando el método Relation::getMorphedModel:

use Illuminate\Database\Eloquent\Relations\Relation;

$alias = $post->getMorphClass();

$class = Relation::getMorphedModel($alias);
Внимание

Al agregar un "morph map" a su aplicación existente, cada valor de columna *_type morphable en su base de datos que aún contenga una clase completamente calificada deberá convertirse a su nombre en el "mapa".

#Relaciones Dinámicas

Puede usar el método resolveRelationUsing para definir relaciones entre modelos Eloquent en tiempo de ejecución. Aunque no se recomienda normalmente para el desarrollo habitual de aplicaciones, esto puede ser útil ocasionalmente al desarrollar paquetes Laravel.

El método resolveRelationUsing acepta el nombre deseado de la relación como primer argumento. El segundo argumento debe ser un closure que recibe la instancia del modelo y devuelve una definición válida de relación Eloquent. Normalmente, debería configurar relaciones dinámicas dentro del método boot de un service provider:

use App\Models\Order;
use App\Models\Customer;

Order::resolveRelationUsing('customer', function (Order $orderModel) {
    return $orderModel->belongsTo(Customer::class, 'customer_id');
});
Внимание

Al definir relaciones dinámicas, siempre proporcione argumentos explícitos para los nombres de claves en los métodos de relación Eloquent.

#Consultando Relaciones

Dado que todas las relaciones Eloquent se definen mediante métodos, puede llamar a esos métodos para obtener una instancia de la relación sin ejecutar realmente una consulta para cargar los modelos relacionados. Además, todos los tipos de relaciones Eloquent también funcionan como query builders, permitiéndole encadenar restricciones a la consulta de la relación antes de ejecutar finalmente la consulta SQL contra su base de datos.

Por ejemplo, imagine una aplicación de blog en la que un modelo User tiene muchos modelos Post asociados:

<?php

namespace App\Models;

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

class User extends Model
{
    /**
     * Obtener todos los posts del usuario.
     */
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}

Puede consultar la relación posts y agregar restricciones adicionales a la relación así:

use App\Models\User;

$user = User::find(1);

$user->posts()->where('active', 1)->get();

Puede usar cualquiera de los métodos del query builder de Laravel en la relación, así que asegúrese de explorar la documentación del query builder para conocer todos los métodos disponibles.

#Encadenando cláusulas orWhere después de relaciones

Como se muestra en el ejemplo anterior, puede agregar restricciones adicionales a las relaciones al consultarlas. Sin embargo, tenga cuidado al encadenar cláusulas orWhere a una relación, ya que las cláusulas orWhere se agruparán lógicamente al mismo nivel que la restricción de la relación:

$user->posts()
        ->where('active', 1)
        ->orWhere('votes', '>=', 100)
        ->get();

El ejemplo anterior generará el siguiente SQL. Como puede ver, la cláusula or indica a la consulta que devuelva cualquier post con más de 100 votos. La consulta ya no está restringida a un usuario específico:

select *
from posts
where user_id = ? and active = 1 or votes >= 100

En la mayoría de las situaciones, debería usar grupos lógicos para agrupar las condiciones entre paréntesis:

use Illuminate\Database\Eloquent\Builder;

$user->posts()
        ->where(function (Builder $query) {
            return $query->where('active', 1)
                         ->orWhere('votes', '>=', 100);
        })
        ->get();

El ejemplo anterior producirá el siguiente SQL. Note que el agrupamiento lógico ha agrupado correctamente las restricciones y la consulta sigue restringida a un usuario específico:

select *
from posts
where user_id = ? and (active = 1 or votes >= 100)

#Métodos de Relación vs. Propiedades Dinámicas

Si no necesita agregar restricciones adicionales a una consulta de relación Eloquent, puede acceder a la relación como si fuera una propiedad. Por ejemplo, continuando con nuestros modelos User y Post, podemos acceder a todos los posts de un usuario así:

use App\Models\User;

$user = User::find(1);

foreach ($user->posts as $post) {
    // ...
}

Las propiedades dinámicas de relaciones realizan "lazy loading", lo que significa que solo cargarán sus datos de relación cuando realmente las acceda. Por esta razón, los desarrolladores suelen usar eager loading para precargar relaciones que saben que serán accedidas después de cargar el modelo. El eager loading reduce significativamente la cantidad de consultas SQL que deben ejecutarse para cargar las relaciones de un modelo.

#Consultando la Existencia de Relaciones

Al recuperar registros de modelos, puede que desee limitar sus resultados basándose en la existencia de una relación. Por ejemplo, imagine que quiere obtener todas las publicaciones de blog que tengan al menos un comentario. Para ello, puede pasar el nombre de la relación a los métodos has y orHas:

use App\Models\Post;

// Obtener todas las publicaciones que tengan al menos un comentario...
$posts = Post::has('comments')->get();

También puede especificar un operador y un valor de conteo para personalizar aún más la consulta:

// Obtener todas las publicaciones que tengan tres o más comentarios...
$posts = Post::has('comments', '>=', 3)->get();

Las sentencias has anidadas pueden construirse usando la notación con "puntos". Por ejemplo, puede obtener todas las publicaciones que tengan al menos un comentario que tenga al menos una imagen:

// Obtener publicaciones que tengan al menos un comentario con imágenes...
$posts = Post::has('comments.images')->get();

Si necesita aún más potencia, puede usar los métodos whereHas y orWhereHas para definir restricciones adicionales en sus consultas has, como inspeccionar el contenido de un comentario:

use Illuminate\Database\Eloquent\Builder;

// Obtener publicaciones con al menos un comentario que contenga palabras como code%...
$posts = Post::whereHas('comments', function (Builder $query) {
    $query->where('content', 'like', 'code%');
})->get();

// Obtener publicaciones con al menos diez comentarios que contengan palabras como code%...
$posts = Post::whereHas('comments', function (Builder $query) {
    $query->where('content', 'like', 'code%');
}, '>=', 10)->get();
Внимание

Actualmente, Eloquent no soporta consultas para la existencia de relaciones entre bases de datos diferentes. Las relaciones deben existir dentro de la misma base de datos.

#Consultas Inline para Existencia de Relaciones

Si desea consultar la existencia de una relación con una sola condición where simple adjunta a la consulta de la relación, puede encontrar más conveniente usar los métodos whereRelation, orWhereRelation, whereMorphRelation y orWhereMorphRelation. Por ejemplo, podemos consultar todas las publicaciones que tengan comentarios no aprobados:

use App\Models\Post;

$posts = Post::whereRelation('comments', 'is_approved', false)->get();

Por supuesto, como en las llamadas al método where del query builder, también puede especificar un operador:

$posts = Post::whereRelation(
    'comments', 'created_at', '>=', now()->subHour()
)->get();

#Consultando la Ausencia de Relaciones

Al recuperar registros de modelos, puede que desee limitar sus resultados basándose en la ausencia de una relación. Por ejemplo, imagine que quiere obtener todas las publicaciones de blog que no tengan ningún comentario. Para ello, puede pasar el nombre de la relación a los métodos doesntHave y orDoesntHave:

use App\Models\Post;

$posts = Post::doesntHave('comments')->get();

Si necesita aún más potencia, puede usar los métodos whereDoesntHave y orWhereDoesntHave para agregar restricciones adicionales a sus consultas doesntHave, como inspeccionar el contenido de un comentario:

use Illuminate\Database\Eloquent\Builder;

$posts = Post::whereDoesntHave('comments', function (Builder $query) {
    $query->where('content', 'like', 'code%');
})->get();

Puede usar la notación con "puntos" para ejecutar una consulta contra una relación anidada. Por ejemplo, la siguiente consulta obtendrá todas las publicaciones que no tengan comentarios; sin embargo, las publicaciones que tengan comentarios de autores que no estén baneados serán incluidas en los resultados:

use Illuminate\Database\Eloquent\Builder;

$posts = Post::whereDoesntHave('comments.author', function (Builder $query) {
    $query->where('banned', 0);
})->get();

#Consultando Relaciones Morph To

Para consultar la existencia de relaciones "morph to", puede usar los métodos whereHasMorph y whereDoesntHaveMorph. Estos métodos aceptan el nombre de la relación como primer argumento. Luego, aceptan los nombres de los modelos relacionados que desea incluir en la consulta. Finalmente, puede proporcionar un closure que personalice la consulta de la relación:

use App\Models\Comment;
use App\Models\Post;
use App\Models\Video;
use Illuminate\Database\Eloquent\Builder;

// Obtener comentarios asociados a posts o videos con un título como code%...
$comments = Comment::whereHasMorph(
    'commentable',
    [Post::class, Video::class],
    function (Builder $query) {
        $query->where('title', 'like', 'code%');
    }
)->get();

// Obtener comentarios asociados a posts con un título no como code%...
$comments = Comment::whereDoesntHaveMorph(
    'commentable',
    Post::class,
    function (Builder $query) {
        $query->where('title', 'like', 'code%');
    }
)->get();

Ocasionalmente puede necesitar agregar restricciones a la consulta basadas en el "tipo" del modelo polimórfico relacionado. El closure pasado al método whereHasMorph puede recibir un valor $type como segundo argumento. Este argumento le permite inspeccionar el "tipo" de la consulta que se está construyendo:

use Illuminate\Database\Eloquent\Builder;

$comments = Comment::whereHasMorph(
    'commentable',
    [Post::class, Video::class],
    function (Builder $query, string $type) {
        $column = $type === Post::class ? 'content' : 'title';

        $query->where($column, 'like', 'code%');
    }
)->get();

En lugar de pasar un arreglo de posibles modelos polimórficos, puede proporcionar * como valor comodín. Esto indicará a Laravel que recupere todos los tipos polimórficos posibles desde la base de datos. Laravel ejecutará una consulta adicional para realizar esta operación:

use Illuminate\Database\Eloquent\Builder;

$comments = Comment::whereHasMorph('commentable', '*', function (Builder $query) {
    $query->where('title', 'like', 'foo%');
})->get();

A veces puede querer contar el número de modelos relacionados para una relación dada sin cargar realmente los modelos. Para lograr esto, puede usar el método withCount. El método withCount colocará un atributo {relation}_count en los modelos resultantes:

use App\Models\Post;

$posts = Post::withCount('comments')->get();

foreach ($posts as $post) {
    echo $post->comments_count;
}

Al pasar un arreglo al método withCount, puede agregar los "conteos" para múltiples relaciones así como agregar restricciones adicionales a las consultas:

use Illuminate\Database\Eloquent\Builder;

$posts = Post::withCount(['votes', 'comments' => function (Builder $query) {
    $query->where('content', 'like', 'code%');
}])->get();

echo $posts[0]->votes_count;
echo $posts[0]->comments_count;

También puede asignar un alias al resultado del conteo de la relación, permitiendo múltiples conteos en la misma relación:

use Illuminate\Database\Eloquent\Builder;

$posts = Post::withCount([
    'comments',
    'comments as pending_comments_count' => function (Builder $query) {
        $query->where('approved', false);
    },
])->get();

echo $posts[0]->comments_count;
echo $posts[0]->pending_comments_count;

#Carga Diferida de Conteo

Usando el método loadCount, puede cargar un conteo de relación después de que el modelo padre ya haya sido recuperado:

$book = Book::first();

$book->loadCount('genres');

Si necesita establecer restricciones adicionales en la consulta de conteo, puede pasar un arreglo con claves de las relaciones que desea contar. Los valores del arreglo deben ser closures que reciben la instancia del query builder:

$book->loadCount(['reviews' => function (Builder $query) {
    $query->where('rating', 5);
}])

#Conteo de Relaciones y Sentencias Select Personalizadas

Si combina withCount con una sentencia select, asegúrese de llamar a withCount después del método select:

$posts = Post::select(['title', 'body'])
                ->withCount('comments')
                ->get();

#Otras Funciones Agregadas

Además del método withCount, Eloquent proporciona los métodos withMin, withMax, withAvg, withSum y withExists. Estos métodos colocarán un atributo {relation}_{function}_{column} en sus modelos resultantes:

use App\Models\Post;

$posts = Post::withSum('comments', 'votes')->get();

foreach ($posts as $post) {
    echo $post->comments_sum_votes;
}

Si desea acceder al resultado de la función agregada usando otro nombre, puede especificar su propio alias:

$posts = Post::withSum('comments as total_comments', 'votes')->get();

foreach ($posts as $post) {
    echo $post->total_comments;
}

Al igual que el método loadCount, también están disponibles versiones diferidas de estos métodos. Estas operaciones agregadas adicionales pueden realizarse en modelos Eloquent que ya han sido recuperados:

$post = Post::first();

$post->loadSum('comments', 'votes');

Si combina estos métodos agregados con una sentencia select, asegúrese de llamar a los métodos agregados después del método select:

$posts = Post::select(['title', 'body'])
                ->withExists('comments')
                ->get();

Si desea eager load una relación "morph to", así como los conteos de modelos relacionados para las diversas entidades que pueden ser devueltas por esa relación, puede utilizar el método with en combinación con el método morphWithCount de la relación morphTo.

En este ejemplo, supongamos que los modelos Photo y Post pueden crear modelos ActivityFeed. Supondremos que el modelo ActivityFeed define una relación "morph to" llamada parentable que nos permite obtener el modelo padre Photo o Post para una instancia dada de ActivityFeed. Además, supongamos que los modelos Photo "tienen muchos" modelos Tag y los modelos Post "tienen muchos" modelos Comment.

Ahora, imaginemos que queremos obtener instancias de ActivityFeed y eager load los modelos padres parentable para cada instancia de ActivityFeed. Además, queremos obtener el número de etiquetas asociadas con cada foto padre y el número de comentarios asociados con cada post padre:

use Illuminate\Database\Eloquent\Relations\MorphTo;

$activities = ActivityFeed::with([
    'parentable' => function (MorphTo $morphTo) {
        $morphTo->morphWithCount([
            Photo::class => ['tags'],
            Post::class => ['comments'],
        ]);
    }])->get();

#Carga Diferida de Conteo

Supongamos que ya hemos recuperado un conjunto de modelos ActivityFeed y ahora queremos cargar los conteos de relaciones anidadas para los diversos modelos parentable asociados con los feeds de actividad. Puede usar el método loadMorphCount para lograr esto:

$activities = ActivityFeed::with('parentable')->get();

$activities->loadMorphCount('parentable', [
    Photo::class => ['tags'],
    Post::class => ['comments'],
]);

#Carga ansiosa (Eager Loading)

Al acceder a relaciones Eloquent como propiedades, los modelos relacionados se cargan "perezosamente" (lazy loaded). Esto significa que los datos de la relación no se cargan realmente hasta que accede por primera vez a la propiedad. Sin embargo, Eloquent puede "eager load" relaciones en el momento en que consulta el modelo padre. El eager loading alivia el problema de consultas "N + 1". Para ilustrar el problema N + 1, considere un modelo Book que "pertenece a" un modelo Author:

<?php

namespace App\Models;

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

class Book extends Model
{
    /**
     * Obtener el autor que escribió el libro.
     */
    public function author(): BelongsTo
    {
        return $this->belongsTo(Author::class);
    }
}

Ahora, obtengamos todos los libros y sus autores:

use App\Models\Book;

$books = Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}

Este ciclo ejecutará una consulta para obtener todos los libros en la tabla de la base de datos, luego otra consulta por cada libro para obtener el autor del libro. Entonces, si tenemos 25 libros, el código anterior ejecutaría 26 consultas: una para los libros y 25 consultas adicionales para obtener el autor de cada libro.

Afortunadamente, podemos usar eager loading para reducir esta operación a solo dos consultas. Al construir una consulta, puede especificar qué relaciones deben ser eager loaded usando el método with:

$books = Book::with('author')->get();

foreach ($books as $book) {
    echo $book->author->name;
}

Para esta operación, solo se ejecutarán dos consultas: una para obtener todos los libros y otra para obtener todos los autores de todos los libros:

select * from books

select * from authors where id in (1, 2, 3, 4, 5, ...)

#Eager Loading de Múltiples Relaciones

A veces puede necesitar eager load varias relaciones diferentes. Para hacerlo, simplemente pase un arreglo de relaciones al método with:

$books = Book::with(['author', 'publisher'])->get();

#Eager Loading Anidado

Para eager load las relaciones de una relación, puede usar la sintaxis con "puntos". Por ejemplo, eager load todos los autores de los libros y todos los contactos personales del autor:

$books = Book::with('author.contacts')->get();

Alternativamente, puede especificar relaciones anidadas eager loaded proporcionando un arreglo anidado al método with, lo cual puede ser conveniente al eager load múltiples relaciones anidadas:

$books = Book::with([
    'author' => [
        'contacts',
        'publisher',
    ],
])->get();

#Eager Loading Anidado de Relaciones morphTo

Si desea eager load una relación morphTo, así como relaciones anidadas en las diversas entidades que pueden ser devueltas por esa relación, puede usar el método with en combinación con el método morphWith de la relación morphTo. Para ilustrar este método, consideremos el siguiente modelo:

<?php

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

class ActivityFeed extends Model
{
    /**
     * Obtener el padre del registro del feed de actividad.
     */
    public function parentable(): MorphTo
    {
        return $this->morphTo();
    }
}

En este ejemplo, supongamos que los modelos Event, Photo y Post pueden crear modelos ActivityFeed. Además, supongamos que los modelos Event pertenecen a un modelo Calendar, los modelos Photo están asociados con modelos Tag y los modelos Post pertenecen a un modelo Author.

Usando estas definiciones de modelos y relaciones, podemos obtener instancias del modelo ActivityFeed y eager load todos los modelos parentable y sus respectivas relaciones anidadas:

use Illuminate\Database\Eloquent\Relations\MorphTo;

$activities = ActivityFeed::query()
    ->with(['parentable' => function (MorphTo $morphTo) {
        $morphTo->morphWith([
            Event::class => ['calendar'],
            Photo::class => ['tags'],
            Post::class => ['author'],
        ]);
    }])->get();

#Eager Loading de Columnas Específicas

No siempre necesitará todas las columnas de las relaciones que está recuperando. Por esta razón, Eloquent le permite especificar qué columnas de la relación desea obtener:

$books = Book::with('author:id,name,book_id')->get();
Внимание

Al usar esta característica, siempre debe incluir la columna id y cualquier columna de clave foránea relevante en la lista de columnas que desea recuperar.

#Eager Loading por Defecto

A veces puede querer cargar siempre algunas relaciones al recuperar un modelo. Para lograr esto, puede definir una propiedad $with en el modelo:

<?php

namespace App\Models;

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

class Book extends Model
{
    /**
     * Las relaciones que siempre deben cargarse.
     *
     * @var array
     */
    protected $with = ['author'];

    /**
     * Obtener el autor que escribió el libro.
     */
    public function author(): BelongsTo
    {
        return $this->belongsTo(Author::class);
    }

    /**
     * Obtener el género del libro.
     */
    public function genre(): BelongsTo
    {
        return $this->belongsTo(Genre::class);
    }
}

Si desea eliminar un elemento de la propiedad $with para una sola consulta, puede usar el método without:

$books = Book::without('author')->get();

Si desea sobrescribir todos los elementos dentro de la propiedad $with para una sola consulta, puede usar el método withOnly:

$books = Book::withOnly('genre')->get();

#Restringiendo Eager Loads

A veces puede querer eager load una relación pero también especificar condiciones adicionales para la consulta de eager loading. Puede lograr esto pasando un arreglo de relaciones al método with donde la clave del arreglo es el nombre de la relación y el valor es un closure que agrega restricciones adicionales a la consulta de eager loading:

use App\Models\User;
use Illuminate\Contracts\Database\Eloquent\Builder;

$users = User::with(['posts' => function (Builder $query) {
    $query->where('title', 'like', '%code%');
}])->get();

En este ejemplo, Eloquent solo cargará eager los posts donde la columna title del post contenga la palabra code. Puede llamar a otros métodos del query builder para personalizar aún más la operación de eager loading:

$users = User::with(['posts' => function (Builder $query) {
    $query->orderBy('created_at', 'desc');
}])->get();
Внимание

Los métodos limit y take del query builder no pueden usarse al restringir eager loads.

#Restringiendo la carga ansiosa de relaciones morphTo

Si está cargando ansiosamente una relación morphTo, Eloquent ejecutará múltiples consultas para obtener cada tipo de modelo relacionado. Puede agregar restricciones adicionales a cada una de estas consultas usando el método constrain de la relación MorphTo:

use Illuminate\Database\Eloquent\Relations\MorphTo;

$comments = Comment::with(['commentable' => function (MorphTo $morphTo) {
    $morphTo->constrain([
        Post::class => function ($query) {
            $query->whereNull('hidden_at');
        },
        Video::class => function ($query) {
            $query->where('type', 'educational');
        },
    ]);
}])->get();

En este ejemplo, Eloquent solo cargará ansiosamente los posts que no han sido ocultados y los videos que tienen un valor type de "educational".

#Restringiendo cargas ansiosas con existencia de relaciones

A veces puede necesitar verificar la existencia de una relación mientras carga ansiosamente la relación basada en las mismas condiciones. Por ejemplo, puede querer recuperar solo los modelos User que tienen modelos hijos Post que coinciden con una condición dada, mientras también carga ansiosamente esos posts coincidentes. Puede lograr esto usando el método withWhereHas:

use App\Models\User;

$users = User::withWhereHas('posts', function ($query) {
    $query->where('featured', true);
})->get();

#Carga ansiosa perezosa (Lazy Eager Loading)

A veces puede necesitar cargar ansiosamente una relación después de que el modelo padre ya ha sido recuperado. Por ejemplo, esto puede ser útil si necesita decidir dinámicamente si cargar modelos relacionados:

use App\Models\Book;

$books = Book::all();

if ($someCondition) {
    $books->load('author', 'publisher');
}

Si necesita establecer restricciones adicionales en la consulta de carga ansiosa, puede pasar un arreglo con claves de las relaciones que desea cargar. Los valores del arreglo deben ser closures que reciben la instancia de la consulta:

$author->load(['books' => function (Builder $query) {
    $query->orderBy('published_date', 'asc');
}]);

Para cargar una relación solo cuando no ha sido cargada previamente, use el método loadMissing:

$book->loadMissing('author');

#Carga ansiosa perezosa anidada y morphTo

Si desea cargar ansiosamente una relación morphTo, así como relaciones anidadas en las diversas entidades que pueden ser retornadas por esa relación, puede usar el método loadMorph.

Este método acepta el nombre de la relación morphTo como primer argumento, y un arreglo de pares modelo / relación como segundo argumento. Para ilustrar este método, consideremos el siguiente modelo:

<?php

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

class ActivityFeed extends Model
{
    /**
     * Obtiene el padre del registro del feed de actividad.
     */
    public function parentable(): MorphTo
    {
        return $this->morphTo();
    }
}

En este ejemplo, supongamos que los modelos Event, Photo y Post pueden crear modelos ActivityFeed. Además, supongamos que los modelos Event pertenecen a un modelo Calendar, los modelos Photo están asociados con modelos Tag, y los modelos Post pertenecen a un modelo Author.

Usando estas definiciones de modelos y relaciones, podemos recuperar instancias del modelo ActivityFeed y cargar ansiosamente todos los modelos parentable y sus respectivas relaciones anidadas:

$activities = ActivityFeed::with('parentable')
    ->get()
    ->loadMorph('parentable', [
        Event::class => ['calendar'],
        Photo::class => ['tags'],
        Post::class => ['author'],
    ]);

#Previniendo la carga perezosa

Como se discutió anteriormente, cargar relaciones ansiosamente puede proporcionar beneficios significativos de rendimiento a su aplicación. Por lo tanto, si lo desea, puede indicarle a Laravel que siempre prevenga la carga perezosa de relaciones. Para lograr esto, puede invocar el método preventLazyLoading que ofrece la clase base del modelo Eloquent. Normalmente, debería llamar a este método dentro del método boot de la clase AppServiceProvider de su aplicación.

El método preventLazyLoading acepta un argumento booleano opcional que indica si se debe prevenir la carga perezosa. Por ejemplo, puede querer deshabilitar la carga perezosa solo en entornos que no sean de producción para que su entorno de producción continúe funcionando normalmente incluso si una relación cargada perezosamente está presente accidentalmente en el código de producción:

use Illuminate\Database\Eloquent\Model;

/**
 * Inicializar cualquier servicio de la aplicación.
 */
public function boot(): void
{
    Model::preventLazyLoading(! $this->app->isProduction());
}

Después de prevenir la carga perezosa, Eloquent lanzará una excepción Illuminate\Database\LazyLoadingViolationException cuando su aplicación intente cargar perezosamente cualquier relación Eloquent.

Puede personalizar el comportamiento de las violaciones de carga perezosa usando el método handleLazyLoadingViolationsUsing. Por ejemplo, usando este método, puede indicar que las violaciones de carga perezosa solo se registren en lugar de interrumpir la ejecución de la aplicación con excepciones:

Model::handleLazyLoadingViolationUsing(function (Model $model, string $relation) {
    $class = $model::class;

    info("Attempted to lazy load [{$relation}] on model [{$class}].");
});

#El método save

Eloquent proporciona métodos convenientes para agregar nuevos modelos a relaciones. Por ejemplo, tal vez necesite agregar un nuevo comentario a un post. En lugar de establecer manualmente el atributo post_id en el modelo Comment, puede insertar el comentario usando el método save de la relación:

use App\Models\Comment;
use App\Models\Post;

$comment = new Comment(['message' => 'A new comment.']);

$post = Post::find(1);

$post->comments()->save($comment);

Note que no accedimos a la relación comments como propiedad dinámica. En cambio, llamamos al método comments para obtener una instancia de la relación. El método save agregará automáticamente el valor apropiado de post_id al nuevo modelo Comment.

Si necesita guardar múltiples modelos relacionados, puede usar el método saveMany:

$post = Post::find(1);

$post->comments()->saveMany([
    new Comment(['message' => 'A new comment.']),
    new Comment(['message' => 'Another new comment.']),
]);

Los métodos save y saveMany persistirán las instancias de modelo dadas, pero no agregarán los modelos recién persistidos a ninguna relación en memoria que ya esté cargada en el modelo padre. Si planea acceder a la relación después de usar los métodos save o saveMany, puede usar el método refresh para recargar el modelo y sus relaciones:

$post->comments()->save($comment);

$post->refresh();

// Todos los comentarios, incluyendo el comentario recién guardado...
$post->comments;

#Guardando modelos y relaciones recursivamente

Si desea save su modelo y todas sus relaciones asociadas, puede usar el método push. En este ejemplo, el modelo Post será guardado junto con sus comentarios y los autores de los comentarios:

$post = Post::find(1);

$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';

$post->push();

El método pushQuietly puede usarse para guardar un modelo y sus relaciones asociadas sin disparar ningún evento:

$post->pushQuietly();

#El método create

Además de los métodos save y saveMany, también puede usar el método create, que acepta un array de atributos, crea un modelo y lo inserta en la base de datos. La diferencia entre save y create es que save acepta una instancia completa de un modelo Eloquent, mientras que create acepta un array simple de PHP. El modelo recién creado será devuelto por el método create:

use App\Models\Post;

$post = Post::find(1);

$comment = $post->comments()->create([
    'message' => 'A new comment.',
]);

Puede usar el método createMany para crear múltiples modelos relacionados:

$post = Post::find(1);

$post->comments()->createMany([
    ['message' => 'A new comment.'],
    ['message' => 'Another new comment.'],
]);

Los métodos createQuietly y createManyQuietly pueden usarse para crear modelo(s) sin despachar ningún evento:

$user = User::find(1);

$user->posts()->createQuietly([
    'title' => 'Post title.',
]);

$user->posts()->createManyQuietly([
    ['title' => 'First post.'],
    ['title' => 'Second post.'],
]);

También puede usar los métodos findOrNew, firstOrNew, firstOrCreate y updateOrCreate para crear y actualizar modelos en relaciones.

Примечание

Antes de usar el método create, asegúrese de revisar la documentación sobre asignación masiva.

#Relaciones Belongs To

Si desea asignar un modelo hijo a un nuevo modelo padre, puede usar el método associate. En este ejemplo, el modelo User define una relación belongsTo con el modelo Account. Este método associate establecerá la clave foránea en el modelo hijo:

use App\Models\Account;

$account = Account::find(10);

$user->account()->associate($account);

$user->save();

Para eliminar un modelo padre de un modelo hijo, puede usar el método dissociate. Este método establecerá la clave foránea de la relación a null:

$user->account()->dissociate();

$user->save();

#Relaciones Many to Many

#Adjuntar / Desadjuntar

Eloquent también proporciona métodos para facilitar el trabajo con relaciones many-to-many. Por ejemplo, imaginemos que un usuario puede tener muchos roles y un rol puede tener muchos usuarios. Puede usar el método attach para adjuntar un rol a un usuario insertando un registro en la tabla intermedia de la relación:

use App\Models\User;

$user = User::find(1);

$user->roles()->attach($roleId);

Al adjuntar una relación a un modelo, también puede pasar un arreglo de datos adicionales para insertar en la tabla intermedia:

$user->roles()->attach($roleId, ['expires' => $expires]);

A veces puede ser necesario eliminar un rol de un usuario. Para eliminar un registro de relación many-to-many, use el método detach. El método detach eliminará el registro apropiado de la tabla intermedia; sin embargo, ambos modelos permanecerán en la base de datos:

// Desadjuntar un solo rol del usuario...
$user->roles()->detach($roleId);

// Desadjuntar todos los roles del usuario...
$user->roles()->detach();

Para mayor comodidad, attach y detach también aceptan arreglos de IDs como entrada:

$user = User::find(1);

$user->roles()->detach([1, 2, 3]);

$user->roles()->attach([
    1 => ['expires' => $expires],
    2 => ['expires' => $expires],
]);

#Sincronizando asociaciones

También puede usar el método sync para construir asociaciones many-to-many. El método sync acepta un arreglo de IDs para colocar en la tabla intermedia. Cualquier ID que no esté en el arreglo dado será eliminado de la tabla intermedia. Así, después de completar esta operación, solo existirán en la tabla intermedia los IDs del arreglo dado:

$user->roles()->sync([1, 2, 3]);

También puede pasar valores adicionales para la tabla intermedia junto con los IDs:

$user->roles()->sync([1 => ['expires' => true], 2, 3]);

Si desea insertar los mismos valores para la tabla intermedia con cada uno de los IDs sincronizados, puede usar el método syncWithPivotValues:

$user->roles()->syncWithPivotValues([1, 2, 3], ['active' => true]);

Si no desea desadjuntar los IDs existentes que faltan en el arreglo dado, puede usar el método syncWithoutDetaching:

$user->roles()->syncWithoutDetaching([1, 2, 3]);

#Alternando asociaciones

La relación many-to-many también proporciona un método toggle que "alternará" el estado de adjunto de los IDs de modelos relacionados dados. Si el ID dado está actualmente adjunto, será desadjuntado. De igual forma, si está desadjuntado, será adjuntado:

$user->roles()->toggle([1, 2, 3]);

También puede pasar valores adicionales para la tabla intermedia junto con los IDs:

$user->roles()->toggle([
    1 => ['expires' => true],
    2 => ['expires' => true],
]);

#Actualizando un registro en la tabla intermedia

Si necesita actualizar una fila existente en la tabla intermedia de su relación, puede usar el método updateExistingPivot. Este método acepta la clave foránea del registro intermedio y un arreglo de atributos para actualizar:

$user = User::find(1);

$user->roles()->updateExistingPivot($roleId, [
    'active' => false,
]);

#Actualizando timestamps del modelo padre

Cuando un modelo define una relación belongsTo o belongsToMany con otro modelo, como un Comment que pertenece a un Post, a veces es útil actualizar el timestamp del padre cuando el modelo hijo es actualizado.

Por ejemplo, cuando un modelo Comment es actualizado, puede querer automáticamente "tocar" el timestamp updated_at del Post propietario para que se establezca en la fecha y hora actuales. Para lograr esto, puede agregar una propiedad touches a su modelo hijo que contenga los nombres de las relaciones cuyos timestamps updated_at deben actualizarse cuando el modelo hijo sea actualizado:

<?php

namespace App\Models;

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

class Comment extends Model
{
    /**
     * Todas las relaciones que deben ser tocadas.
     *
     * @var array
     */
    protected $touches = ['post'];

    /**
     * Obtener el post al que pertenece el comentario.
     */
    public function post(): BelongsTo
    {
        return $this->belongsTo(Post::class);
    }
}
Внимание

Los timestamps del modelo padre solo se actualizarán si el modelo hijo es actualizado usando el método save de Eloquent.