Introducción

Las tablas de base de datos frecuentemente están relacionadas a otra tabla. Por ejemplo, un post de un blog puede tener muchos comentarios o un pedido podría estar relacionado al usuario que lo ordenó. Eloquent hace que manejar y trabajar con estas relaciones sea fácil y soporta varios tipos de relaciones:

Definiendo relaciones

Las relaciones de Eloquent se definen como métodos en tus clases de modelo de Eloquent. Debido a que, como los mismos modelos Eloquent, las relaciones también sirven como poderosos constructores de consultas, el definir relaciones como métodos proporciona potentes capacidades de encadenamiento de métodos y consultas. Por ejemplo, podemos encadenar restricciones adicionales en esta relación posts:

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

Pero, antes de profundizar demasiado en el uso de relaciones, aprendamos cómo definir cada tipo.

Los nombres de las relaciones no pueden colisionar con nombres de atributos dado que eso podría ocasionar que tu modelo no sea capaz de saber cuál resolver.

Uno A Uno

Una relación de uno a uno es una relación muy sencilla. Por ejemplo, un modelo User podría estar asociado con un Phone. Para definir esta relación, colocaremos un método phone en el modelo User. El método phone debería llamar al método hasOne y devolver su resultado:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
    * Get the phone record associated with the user.
    */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

El primer argumento pasado al método hasOne es el nombre del modelo relacionado. Una vez que la relación es definida, podemos obtener el registro relacionado usando propiedades dinámicas de Eloquent. Las propiedades dinámicas permiten que accedas a 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 en base al nombre del modelo. En este caso, se asume automáticamente que el modelo Phone tenga una clave foránea user_id. Si deseas sobrescribir esta convención, puedes pasar un segundo argumento al método hasOne:

return $this->hasOne('App\Phone', 'foreign_key');

Adicionalmente, Eloquent asume que la clave foránea debería tener un valor que coincida con la columna id (o $primaryKey personalizada) del padre. En otras palabras, Eloquent buscará el valor de la columna id del usuario en la columna user_id de Phone. Si prefieres que la relación use un valor distinto de id, puedes pasar un tercer argumento al método hasOne especificando tu clave personalizada:

return $this->hasOne('App\Phone', 'foreign_key', 'local_key');

Definiendo el inverso de la relación

Así, podemos acceder al modelo Phone desde nuestro User. Ahora, vamos a definir una relación en el modelo Phone que nos permitirá acceder al User que posee el teléfono. Podemos definir el inverso de una relación hasOne usando el método belongsTo:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Phone extends Model
{
    /**
    * Get the user that owns the phone.
    */
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

En el ejemplo anterior, Eloquent intentará hacer coincidir el user_id del modelo Phone con un id en el modelo User. Eloquent determina el nombre de la clave foránea de forma predeterminada al examinar el nombre del método de la relación y agregando el sufijo al nombre del método con _id. Sin embargo, si la clave foránea en el modelo Phone no es user_id, puedes pasar un nombre de clave personalizada como segundo argumento al método belongsTo:

/**
* Get the user that owns the phone.
*/
public function user()
{
    return $this->belongsTo('App\User', 'foreign_key');
}

Si tu modelo padre no usa id como su clave primaria, o deseas hacer join al modelo hijo con una columna diferente, puedes pasar un tercer argumento al método belongsTo especificando la clave personalizada de tu tabla padre:

/**
* Get the user that owns the phone.
*/
public function user()
{
    return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}

Uno a muchos

Una relación de «uno-a-muchos» es usada para definir relaciones donde un solo modelo posee cualquier cantidad de otros modelos. Por ejemplo, un post de un blog puede tener un número infinito de comentarios. Al igual que todas las demás relaciones de Eloquent, las relaciones uno-a-muchos son definidas al colocar una función en tu modelo Eloquent:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
    * Get the comments for the blog post.
    */
    public function comments()
    {
        return $this->hasMany('App\Comment');
    }
}

Recuerda, Eloquent determinará automáticamente la columna de clave foránea apropiada en el modelo Comment. Por convención, Eloquent tomará el nombre «snake case» del modelo que la contiene y le agregará el sufijo _id. Para este ejemplo, Eloquent asumirá que la clave foránea del modelo Comment es post_id.

Una vez que la relación ha sido definida, podemos acceder a la colección de comentarios al acceder a la propiedad comments. Recuerda, ya que Eloquent proporciona «propiedades dinámicas», podemos acceder a los métodos de la relación como si fueran definidos como propiedades en el modelo:

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

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

Debido a que todas las relaciones también sirven como constructores de consultas (query builders), puedes agregar restricciones adicionales a cuyos comentarios sean obtenidos ejecutando el método comments y encadenando condiciones en la consulta:

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

Igual que el método hasOne, también puedes sobrescribir las claves foráneas y locales al pasar argumentos adicionales al método hasMany:

return $this->hasMany('App\Comment', 'foreign_key');

return $this->hasMany('App\Comment', 'foreign_key', 'local_key');

Uno a muchos (inverso)

Ahora que puedes acceder a todos los comentarios de un post, vamos a definir una relación para permitir a un comentario acceder a su post padre. Para definir el inverso de una relación hasMany, define una función de relación en el modelo hijo que ejecute el método belongsTo:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
    * Get the post that owns the comment.
    */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

Una vez que la relación ha sido definida, podemos obtener el modelo Post para un Comment accediendo a la «propiedad dinámica» de post:

$comment = App\Comment::find(1);

echo $comment->post->title;

En el ejemplo anterior, Eloquent tratará de hacer coincidir el post_id del modelo Comment con un id en el modelo Post. Eloquent determina el nombre de la clave foránea por defecto, examinando el nombre del método de la relación y agregando un sufijo _ al nombre del método, seguido del nombre de la columna principal de la llave. Sin embargo, si la clave foránea en el modelo Comment no es post_id, puedes pasar un nombre de clave personalizado como segundo argumento al método belongsTo:

/**
* Get the post that owns the comment.
*/
public function post()
{
    return $this->belongsTo('App\Post', 'foreign_key');
}

Si tu modelo padre no usa id como su clave primaria, o deseas hacer join al modelo hijo con una columna diferente, puedes pasar un tercer argumento al método belongsTo especificando la clave personalizada de tu tabla padre.

/**
* Get the post that owns the comment.
*/
public function post()
{
    return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
}

Muchos a muchos

Las relaciones de muchos-a-muchos son ligeramente más complicadas que las relaciones hasOne y hasMany. Un ejemplo de tal relación es un usuario con muchos roles, donde los roles también son compartidos por otros usuarios. Por ejemplo, muchos usuarios pueden tener el rol «Admin».

Estructura de la tabla

Para definir esta relación, tres tablas de bases de datos son necesitadas: users, roles, y role_user. La tabla role_user es derivada del orden alfabético de los nombres de modelo relacionados y contiene las columnas user_id y role_id.

users
    id - integer
    name - string

roles
    id - integer
    name - string

role_user
    user_id - integer
    role_id - integer

Estructura del modelo

Las relaciones de muchos-a-muchos son definidas escribiendo un método que devuelve el resultado del método belongsToMany. Por ejemplo, vamos a definir el método roles en nuestro modelo User:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
    * The roles that belong to the user.
    */
    public function roles()
    {
        return $this->belongsToMany('App\Role');
    }
}

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

$user = App\User::find(1);

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

Como con los otros tipos de relación, puedes ejecutar el método roles para continuar encadenando las restricciones de consulta en la relación:

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

Como mencionamos previamente, para determinar el nombre de la tabla asociativa, Eloquent juntará los dos nombres de modelo en orden alfabético. Sin embargo, eres libre de sobrescribir esta convención. Puedes hacer eso pasando un segundo argumento al método belongsToMany:

return $this->belongsToMany('App\Role', 'role_user');

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

return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');

Definiendo el inverso de la relación

Para definir el inverso de una relación de muchos-a-muchos, puedes colocar otra llamada de belongsToMany en tu modelo relacionado. Para continuar con nuestro ejemplo de roles de usuario, vamos a definir el método users en el modelo Role:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    /**
    * The users that belong to the role.
    */
    public function users()
    {
        return $this->belongsToMany('App\User');
    }
}

Como puedes ver, la relación es definida exactamente de la misma forma que su contraparte User, con la excepción de que referencia al modelo App\User. Ya que estamos reusando el método belongsToMany, todas las tablas y opciones de personalización de claves usuales están disponibles al momento de definir el inverso de las relaciones de muchos-a-muchos.

Obteniendo columnas de tablas intermedias (Pivote)

Como ya has aprendido, trabajar con relaciones de muchos-a-muchos requiere la presencia de una tabla intermedia o pivote. Eloquent proporciona algunas formas muy útiles de interactuar con esta tabla. Por ejemplo, vamos a asumir que nuestro objeto User tiene muchos objetos Role al que está relacionado. Después de acceder a esta relación, podemos acceder a la tabla intermedia usando el atributo pivot en los modelos:

$user = App\User::find(1);

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

Ten en cuenta que a cada modelo Role que obtenemos se le asigna automáticamente un atributo pivot. Este atributo contiene un modelo que representa la tabla intermedia y puede ser usado como cualquier otro modelo de Eloquent.

De forma predeterminada, solo las claves del modelo estarán presentes en el objeto pivot. Si tu tabla pivote contiene atributos extras, debes especificarlos cuando definas la relación.

return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

Si quieres que tu tabla pivote automáticamente mantenga las marcas de tiempo created_at y updated_at, usa el método withTimestamps en la definición de la relación:

return $this->belongsToMany('App\Role')->withTimestamps();

Personalizando el nombre del atributo pivot

Como se señaló anteriormente, los atributos de la tabla intermedia pueden ser accedidos en modelos usando el atributo pivot. Sin embargo, eres libre de personalizar el nombre de este atributo para que refleje mejor su propósito dentro de tu aplicación.

Por ejemplo, si tu aplicación contiene usuarios que pueden suscribirse a podcasts, probablemente tengas una relación de muchos-a-muchos entre usuarios y podcasts. Si éste es el caso, puedes desear renombrar tu tabla pivote intermedia como subscription en lugar de pivot. Esto se puede hacer usando el método as al momento de definir la relación:

return $this->belongsToMany('App\Podcast')
                ->as('subscription')
                ->withTimestamps();

Una vez hecho esto, puedes 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 relaciones a través de columnas de tablas intermedias

También puedes filtrar los resultados devueltos por belongsToMany usando los métodos wherePivot, wherePivotIn y wherePivotNotIn al momento de definir la relación:

return $this->belongsToMany('App\Role')->wherePivot('approved', 1);

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

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

Definiendo modelos de tabla intermedia personalizados

Si prefieres definir un modelo personalizado para representar la tabla intermedia o pivote de tu relación, puedes ejecutar el método using al momento de definir la relación. Los modelos de tablas intermedias de muchos-a-muchos personalizados deben extender la clase Illuminate\Database\Eloquent\Relations\Pivot mientras que los modelos polimórficos muchos-a-muchos deben extender la clase Illuminate\Database\Eloquent\Relations\MorphPivot. Por ejemplo, podemos definir un Role que use un modelo pivote RoleUser personalizado:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    /**
    * The users that belong to the role.
    */
    public function users()
    {
        return $this->belongsToMany('App\User')->using('App\RoleUser');
    }
}

Al momento de definir el modelo RoleUser, extenderemos la clase Pivot:

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot
{
    //
}

Puedes combinar using y withPivot para retornar columnas de la tabla intermedia. Por ejemplo, puedes retornar las columnas created_by y updated_by desde la tabla pivote RoleUser pasando los nombres de las columnas al método withPivot:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    /**
    * The users that belong to the role.
    */
    public function users()
    {
        return $this->belongsToMany('App\User')
                        ->using('App\RoleUser')
                        ->withPivot([
                            'created_by',
                            'updated_by',
                        ]);
    }
}

Nota: Los modelos Pivot no pueden usar el trait SoftDeletes. Si necesitas hacer eliminación lógica (soft delete) de registros pivot considera convertir tu modelo pivot a un modelo de Eloquent.

Modelos de pivote personalizados e IDs incrementales

Si has definido una relación de muchos a muchos que usa un modelo de pivote personalizado, y ese modelo de pivote tiene una clave primaria de incremento automático, debes asegurarte de que su clase de modelo de pivote personalizado defina una propiedad incrementing que se establece en true.

/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = true;

Tiene uno a través de (hasOneThrough)

La relación «tiene-uno-a-través-de» vincula los modelos a través de una única relación intermedia.
Por ejemplo, si cada proveedor (supplier) tiene un usuario (user) y cada usuario está asociado con un registro del historial (history) de usuarios, entonces el modelo del proveedor puede acceder al historial del usuario a través del usuario. Veamos las tablas de base de datos necesarias para definir esta relación:

users
    id - integer
    supplier_id - integer

suppliers
    id - integer

history
    id - integer
    user_id - integer

Aunque la tabla history no contiene una columna supplier_id, la relación hasOneThrough puede proporcionar acceso al historial del usuario desde el modelo del proveedor. Ahora que hemos examinado la estructura de la tabla para la relación, vamos a definirla en el modelo Supplier:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Supplier extends Model
{
    /**
    * Get the user's history.
    */
    public function userHistory()
    {
        return $this->hasOneThrough('App\History', 'App\User');
    }
}

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

Se utilizarán las convenciones típicas de clave foránea de Eloquent al realizar las consultas de la relación. Si deseas personalizar las claves de la relación, puedes pasarlas como el 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 Supplier extends Model
{
    /**
    * Get the user's history.
    */
    public function userHistory()
    {
        return $this->hasOneThrough(
            'App\History',
            'App\User',
            'supplier_id', // Foreign key on users table...
            'user_id', // Foreign key on history table...
            'id', // Local key on suppliers table...
            'id' // Local key on users table...
        );
    }
}

Tiene muchos a través de (hasManyThrough)

La relación «tiene-muchos-a-través-de» proporciona una abreviación conveniente para acceder a relaciones distantes por medio de una relación intermedia. Por ejemplo, un modelo Country podría tener muchos modelos Post a través de un modelo User intermedio. En este ejemplo, podrías traer todos los posts de un blog para un país dado. Vamos a buscar las tablas requeridas para definir esta relación:

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string

Aunque los posts no contienen una columna country_id, la relación hasManyThrough proporciona acceso a los posts de un país por medio de $country->posts. Para ejecutar esta consulta, Eloquent inspecciona el country_id de la tabla intermedia users. Después de encontrar los ID de usuario que coincidan, serán usados para consultar la tabla posts.

Ahora que hemos examinado la estructura de la tabla para la relación, vamos a definirla en el modelo Country:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Country extends Model
{
    /**
    * Get all of the posts for the country.
    */
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User');
    }
}

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

Las convenciones de clave foránea típicas de Eloquent serán usadas al momento de ejecutar las consultas de la relación. Si prefieres personalizar las claves de la relación, puedes pasarlos como tercer y cuarto argumentos del 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 el sexto argumento es la clave local del modelo intermedio:

class Country extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(
            'App\Post',
            'App\User',
            'country_id', // Foreign key on users table...
            'user_id', // Foreign key on posts table...
            'id', // Local key on countries table...
            'id' // Local key on users table...
        );
    }
}

Relaciones polimórficas

Una relación polimórfica permite que el modelo objetivo pertenezca a más de un tipo de modelo usando una sola asociación.

Una a una (polimórfica)

Estructura de tabla

Una relación polimórfica de uno-a-uno es similar a una relación de uno-a-uno simple; sin embargo, el modelo objetivo puede pertenecer a más de un tipo de modelo en una sola asociación. Por ejemplo, un Post de un blog y un User pueden compartir una relación polimórfica con un modelo Image. El uso de una relación polimórfica de uno-a-uno te permite tener una sola lista de imágenes únicas que son usadas tanto por los posts del blog como por las cuentas de los usuarios. Primero, vamos a examinar 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

Observa las columnas imageable_id y imageable_type en la tabla images. La columna imageable_id contendrá el valor del ID del post o del usuario, mientras que la columna imageable_type contendrá el nombre de clase del modelo padre. La columna imageable_type es usada por Eloquent para determinar cuál «tipo» de modelo padre retornar al acceder a la relación imageable.

Estructura del modelo

A continuación, vamos a examinar las definiciones de modelo necesarias para construir esta relación:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Image extends Model
{
    /**
    * Get the owning imageable model.
    */
    public function imageable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    /**
    * Get the post's image.
    */
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable');
    }
}

class User extends Model
{
    /**
    * Get the user's image.
    */
    public function image()
    {
        return $this->morphOne('App\Image', 'imageable');
    }
}

Retornando la relación

Una vez que tu tabla en la base de datos y modelos son definidos, puedes acceder a las relaciones mediante tus modelos. Por ejemplo, para retornar la imagen para un post, podemos usar la propiedad dinámica image:

$post = App\Post::find(1);

$image = $post->image;

Puedes también retornar el padre del modelo polimórfico accediendo al nombre del método que realiza la llamada a morphTo. En nuestro caso, éste es el método imageable en el modelo Image. Entonces, accederemos al método como una propiedad dinámica:

$image = App\Image::find(1);

$imageable = $image->imageable;

La relación imageable en el modelo Image retornará ya sea una instancia de Post o User, dependiendo del tipo de modelo que posea la imagen.

Uno a muchos (Polimórfica)

Estructura de tabla

Una relación polimórfica de uno-a-muchos es similar a una relación de uno-a-muchos sencilla; sin embargo, el modelo objetivo puede pertenecer a más de un tipo de modelo en una sola asociación. Por ejemplo, imagina que usuarios de tu aplicación pueden «comentar» tanto en posts como en videos. Usando relaciones polimórficas, puedes usar una sola tabla comments para ambos escenarios. Primero, vamos a examinar la estructura de tabla requerida para 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 de modelo

A continuación, vamos a examinar las definiciones de modelos necesarias para construir esta relación:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
    * Get the owning commentable model.
    */
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    /**
    * Get all of the post's comments.
    */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

class Video extends Model
{
    /**
    * Get all of the video's comments.
    */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

Retornando la relación

Una vez que tu tabla en la base de datos y modelos son definidos, puedes acceder a las relaciones mediante tus modelos. Por ejemplo, para acceder a todos los comentarios de un post, podemos usar la propiedad dinámica comments:

$post = App\Post::find(1);

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

También puedes retornar al propietario de una relación polimórfica desde un modelo polimórfico accediendo al nombre del método que realiza la llamada a morphTo. En nuestro caso, éste es el método commentable en el modelo Comment. Así que, accederemos a dicho método como una propiedad dinámica:

$comment = App\Comment::find(1);

$commentable = $comment->commentable;

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

Muchos A Muchos (Polimórfica)

Estructura de tabla

Las relaciones polimórficas de muchos-a-muchos son un poco más complicadas que las relaciones morphOne y morphMany. Por ejemplo, un modelo Post de un blog y un modelo Video pueden compartir una relación polimórfica con un modelo Tag. El uso de una relación polimórfica de muchos-a-muchos te permite tener una única lista de etiquetas que son compartidas a través de posts y videos. Primero, vamos a examinar la estructura de tabla:

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

Estructura del modelo

Seguidamente, estamos listos para definir las relaciones en el modelo. Ambos modelos Post y Video tendrán un método tags que ejecuta el método morphToMany en la clase base de Eloquent:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
    * Get all of the tags for the post.
    */
    public function tags()
    {
        return $this->morphToMany('App\Tag', 'taggable');
    }
}

Definiendo el inverso de la relación

A continuación, en el modelo Tag, debes definir un método para cada uno de sus modelos relacionados. Así, para este ejemplo, definiremos un método posts y un método videos:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    /**
    * Get all of the posts that are assigned this tag.
    */
    public function posts()
    {
        return $this->morphedByMany('App\Post', 'taggable');
    }

    /**
    * Get all of the videos that are assigned this tag.
    */
    public function videos()
    {
        return $this->morphedByMany('App\Video', 'taggable');
    }
}

Obteniendo la relación

Una vez que tu tabla en la base de datos y modelos son definidos, puedes acceder a las relaciones mediante tus modelos. Por ejemplo, para acceder a todos los tags de un post, puedes usar la propiedad dinámica tags:

$post = App\Post::find(1);

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

También puedes obtener el propietario de una relación polimórfica desde el modelo polimórfico accediendo al nombre del método que realiza la llamada a morphedByMany. En nuestro caso, estos son los métodos posts o videos en el modelo Tag. Así, accederemos a esos métodos como propiedades dinámicas:

$tag = App\Tag::find(1);

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

Tipos polimórficos personalizados

Por defecto, Laravel usará el nombre completo de clase para almacenar el tipo del modelo relacionado. Por ejemplo, dado el ejemplo uno-a-muchos de arriba donde un Comment puede pertenecer a un Post o a un Video, el commentable_type por defecto será App\Post o App\Video, respectivamente. Sin embargo, puedes querer desacoplar tu base de datos de la estructura interna de tu aplicación. En dicho caso, puedes definir un «mapa de morfología (morph map)» para indicarle a Eloquent que use un nombre personalizado para cada modelo en lugar del nombre de la clase:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([
    'posts' => 'App\Post',
    'videos' => 'App\Video',
]);

Puedes registrar el morphMap en la función boot de tu AppServiceProvider o crear un Service Provider independiente si lo deseas.

Al agregar un «morph map» a tu aplicación existente, cada valor de la columna de morfología *_type en tu base de datos que aún contenga una clase completamente calificada necesitará ser convertida a su nombre de «mapa».

Consultando relaciones

Ya que todos los tipos de relaciones Eloquent son definidas por medio de métodos, puedes ejecutar esos métodos para obtener una instancia de la relación sin ejecutar realmente las consultas de la relación. Además, todos los tipos de relaciones Eloquent también sirven como constructores de consultas, permitiendo que continúes encadenando restricciones dentro de la consulta de la relación antes de ejecutar finalmente el SQL contra la base de datos.

Por ejemplo, imagina un sistema de blog en el cual un modelo User tiene muchos modelos Post asociados:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
    * Get all of the posts for the user.
    */
    public function posts()
    {
        return $this->hasMany('App\Post');
    }
}

Puedes consultar la relación posts y agregar limitaciones a la relación de la siguiente forma:

$user = App\User::find(1);

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

Puedes usar cualquiera de los métodos de constructor de consultas en la relación, así que asegúrate de revisar la documentación del constructor de consultas para aprender sobre todos los métodos disponibles.

Encadenando cláusulas orWhere en relaciones

Como se demostró en el ejemplo superior, eres libre de agregar restriciones adicionales a las relaciones al momento de realizar peticiones. Sin embargo, ten cuidado al encadenar cláusulas orWhere a una relación, dado que las cláusulas orWhere serán agrupadas lógicamente en el mismo nivel que la restricción de la relación:

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

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

En la mayoría de los casos, probablemente pretendes usar grupos de restricciones para agrupar lógicamente las comprobaciones condicionales entre paréntesis:

use Illuminate\Database\Eloquent\Builder;

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

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

Métodos de relación Vs. propiedades dinámicas

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

$user = App\User::find(1);

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

Las propiedades dinámicas son de «carga diferida (lazy loading)», lo que significa que cargarán solamente los datos de su relación cuando realmente accedas a ellas. Debido a esto, los desarrolladores con frecuencia usan carga previa (eager loading) para precargar las relaciones que ellos saben que serán accedidas después de cargar el modelo. La carga previa proporciona una reducción significativa en consultas SQL que deben ser ejecutadas para cargar las relaciones de un modelo.

Consultando la existencia de una relación

Cuando accedes a los registros de un modelo, puedes desear limitar sus resultados basados en la existencia de una relación. Por ejemplo, imagina que quieres obtener todos los posts de blog que tienen al menos un comentario. Para hacer eso, puedes pasar el nombre de la relación a los métodos has y orHas:

// Retrieve all posts that have at least one comment...
$posts = App\Post::has('comments')->get();

También puedes especificar un operador y la cantidad para personalizar aún más la consulta:

// Retrieve all posts that have three or more comments...
$posts = App\Post::has('comments', '>=', 3)->get();

Las instrucciones has anidadas también pueden ser construidas usando la notación de «punto». Por ejemplo, puedes obtener todos los posts que tienen al menos un comentario con votos:

// Retrieve posts that have at least one comment with votes...
$posts = App\Post::has('comments.votes')->get();

Incluso si necesitas más potencia, puedes usar los métodos whereHas y orWhereHas para poner condiciones «where» en tus consultas has. Estos métodos permiten que agregues restricciones personalizadas a una restricción de relación, tal como verificar el contenido de un comentario:

use Illuminate\Database\Eloquent\Builder;

// Retrieve posts with at least one comment containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
    $query->where('content', 'like', 'foo%');
})->get();

// Retrieve posts with at least ten comments containing words like foo%...
$posts = App\Post::whereHas('comments', function (Builder $query) {
    $query->where('content', 'like', 'foo%');
}, '>=', 10)->get();

Consultando la ausencia de una relación

Al momento de acceder a los registros de un modelo, puedes desear limitar tus resultados en base a la ausencia de una relación. Por ejemplo, imagina que quieras obtener todos los posts de blogs que no tienen algún comentario. Para hacer eso, puedes pasar el nombre de la relación a los métodos doesntHave y orDoesntHave:

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

Incluso si necesitas más potencia, puedes usar los métodos whereDoesntHave y orWhereDoesntHave para poner condiciones «where» en tus consultas doesntHave. Estos métodos permiten que agregues restricciones personalizadas a una restricción de relación, tal como verificar el contenido de un comentario:

use Illuminate\Database\Eloquent\Builder;

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

Puedes usar notación «de puntos» para ejecutar una consulta contra una relación anidada. Por ejemplo, la siguiente consulta entregará todos los posts con comentarios de autores que no están vetados:

use Illuminate\Database\Eloquent\Builder;

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

Consultando relaciones polimórficas

Para consultar la existencia de relaciones MorphTo, puedes usar el método whereHasMorph y sus métodos correspondientes:

use Illuminate\Database\Eloquent\Builder;

// Retrieve comments associated to posts or videos with a title like foo%...
$comments = App\Comment::whereHasMorph(
    'commentable',
    ['App\Post', 'App\Video'],
    function (Builder $query) {
        $query->where('title', 'like', 'foo%');
    }
)->get();

// Retrieve comments associated to posts with a title not like foo%...
$comments = App\Comment::whereDoesntHaveMorph(
    'commentable',
    'App\Post',
    function (Builder $query) {
        $query->where('title', 'like', 'foo%');
    }
)->get();

Puedes usar el parametro $type para agregar diferentes restricciones dependiendo del modelo relacionado:

use Illuminate\Database\Eloquent\Builder;

$comments = App\Comment::whereHasMorph(
    'commentable',
    ['App\Post', 'App\Video'],
    function (Builder $query, $type) {
        $query->where('title', 'like', 'foo%');

        if ($type === 'App\Post') {
            $query->orWhere('content', 'like', 'foo%');
        }
    }
)->get();

En lugar de pasar un arreglo de posibles modelos polimórficos, puedes proporcionar un * como comodín y dejar que Laravel retorne todos los posibles tipos polimórficos desde la base de datos. Laravel ejecutará una solicitud adicional para poder realizar esta operación:

use Illuminate\Database\Eloquent\Builder;

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

Contando modelos relacionados

Si quieres contar el número de resultados de una relación sin cargarlos realmente puedes usar el método withCount, el cual coloca una columna {relation}_count en tus modelos resultantes. Por ejemplo:

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

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

Puedes agregar las «cuentas» para múltiples relaciones así como también agregar restricciones a las consultas:

use Illuminate\Database\Eloquent\Builder;

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

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

También puedes poner un alias al resultado de la cuenta de la relación, permitiendo múltiples cuentas en la misma relación:

use Illuminate\Database\Eloquent\Builder;

$posts = App\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;

Si estás combinando withCount con una instrucción select, asegúrate de llamar a withCount después del método select:

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

echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;

Además, utilizando el método loadCount, puedes cargar un conteo de la relación después de que el modelo padre haya sido obtenido:

$book = App\Book::first();

$book->loadCount('genres');

Si necesitas establecer restricciones adicionales de consulta en la consulta de carga previa, puedes pasar un arreglo asociativo cuyas claves serán las relaciones que deseas cargar. Los valores del arreglo deben ser instancias de Closure que reciben la instancia del generador de consulta:

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

Carga previa (eager loading)

Al momento de acceder a las relaciones Eloquent como propiedades, los datos de la relación son «cargados diferidamente (lazy loading)». Esto significa que los datos de la relación no son cargados realmente hasta que primero accedas a la propiedad. Sin embargo, Eloquent puede «cargar previamente (eager loading)» las relaciones al mismo tiempo que consultas el modelo padre. La carga previa alivia el problema de la consulta N + 1. Para ilustrar el problema de la consulta N + 1, considera un modelo Book que está relacionado a Author:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
    * Get the author that wrote the book.
    */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

Ahora, vamos a obtener todos los libros y sus autores:

$books = App\Book::all();

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

Este ciclo ejecutará una consulta para obtener todos los libros en la tabla, después otra consulta para cada libro para obtener el autor. Así, si tenemos 25 libros, este ciclo debería ejecutar 26 consultas: 1 para el libro original y 25 consultas adicionales para obtener el autor de cada libro.

Afortunadamente, podemos usar la carga previa para reducir esta operación a solo 2 consultas. Al momento de consultar, puedes especificar cuáles relaciones deberían ser precargadas usando el método with:

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

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

Para esta operación, solo dos consultas serán ejecutadas:

select * from books

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

Carga previa de múltiples relaciones

Algunas veces puedes necesitar la carga previa de varias relaciones diferentes en una operación única. Para hacer eso, pasa sólo los argumentos adicionales al método with:

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

Carga previa anidada

Para precargar relaciones anidadas, puedes usar la sintaxis de «punto». Por ejemplo, vamos a precargar todos los autores de los libros y todos los contactos personales del autor en una instrucción de Eloquent:

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

Carga previa anidada de relaciones morphTo

Si deseas cargar previamente una relación morphTo, así como relaciones anidadas en varias entidades que podrían ser retornadas por dicha relación, puedes usar el método with en combinación con el método morphWith de la relación morphTo. Para ayudarte a ilustrar este método, vamos a considerar el siguiente modelo:

<?php

use Illuminate\Database\Eloquent\Model;

class ActivityFeed extends Model
{
    /**
    * Get the parent of the activity feed record.
    */
    public function parentable()
    {
        return $this->morphTo();
    }
}

En este ejemplo, vamos a asumir que los modelos Event, Photo y Post pueden crear modelos ActivityFeed. Adicionalmente, vamos a asumir que los modelos Event pertenecen a un modelo Calendar, que 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 retornar instancias del modelo ActivityFeed y cargar previamente 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();

Cargando previamente columnas específicas

No siempre necesitarás todas las columnas de las relaciones que estás obteniendo. Por esta razón, Eloquent te permite especificar cuáles columnas de la relación te gustaría obtener:

$books = App\Book::with('author:id,name')->get();

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

Carga previa por defecto

Algunas veces podrías querer cargar siempre algunas relaciones al retornar un modelo. Para lograr esto, puedes definir una propiedad $with en el modelo:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
    * The relationships that should always be loaded.
    *
    * @var array
    */
    protected $with = ['author'];

    /**
    * Get the author that wrote the book.
    */
    public function author()
    {
        return $this->belongsTo('App\Author');
    }
}

Si te gustaria remover un elemento de la propiedad $with para una sola petición, puedes usar el método without:

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

Restringiendo cargas previas

Algunas veces puedes desear cargar previamente una relación, pero también especificar condiciones de consulta adicionales para la consulta de carga previa. Aquí está un ejemplo:

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

En este ejemplo, Eloquent solamente precargará los posts donde la columna title del post contenga la palabra first. Puedes ejecutar otros métodos del constructor de consulta para personalizar más la operación de carga previa:

$users = App\User::with(['posts' => function ($query) {
    $query->orderBy('created_at', 'desc');
}])->get();

Los métodos del constructor de consultas limit y take no se pueden usar al restringir las cargas previas.

Carga previa diferida (lazy eager loading)

Algunas veces puedes necesitar precargar una relación después de que el modelo padre ya ha sido obtenido. Por ejemplo, esto puede ser útil si necesitas decidir dinámicamente si se cargan modelos relacionados:

$books = App\Book::all();

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

Si necesitas establecer restricciones de consultas adicionales en la consulta de carga previa, puedes pasar un arreglo asociativo cuyas claves son las relaciones que deseas cargar. Los valores del arreglo deberían ser instancias de Closure, las cuales reciben la instancia de consulta:

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

Para cargar una relación sólo cuando aún no se ha cargado, usa el método loadMissing:

public function format(Book $book)
{
    $book->loadMissing('author');

    return [
        'name' => $book->name,
        'author' => $book->author->name,
    ];
}

Carga previa diferida anidada y morphTo

Si deseas cargar previamente una relación morphTo, así como relaciones anidadas en las diversas entidades que pueden ser devueltas por esa relación, puedes usar el método loadMorph.

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

<?php

use Illuminate\Database\Eloquent\Model;

class ActivityFeed extends Model
{
    /**
    * Get the parent of the activity feed record.
    */
    public function parentable()
    {
        return $this->morphTo();
    }
}

En este ejemplo, asumamos 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 los 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 cargar previamente 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'],
    ]);

Insertando y actualizando modelos relacionados

El método save

Eloquent proporciona métodos convenientes para agregar nuevos modelos a las relaciones. Por ejemplo, quizá necesites insertar un nuevo Comment para un modelo Post. En lugar de establecer manualmente el atributo post_id en el Comment, puedes insertar el Comment directamente con el método save de la relación:

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

$post = App\Post::find(1);

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

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

Si necesitas guardar múltiples modelos relacionados, puedes usar el método saveMany:

$post = App\Post::find(1);

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

Guardando modelos y relaciones recursivamente

Si quieres hacer save a tu modelo y a todas sus relaciones asociadas, puedes usar el método push:

$post = App\Post::find(1);

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

$post->push();

El método create

Además de los métodos save y saveMany, también puedes usar el método create, el cual acepta un arreglo de atributos, crea un modelo y lo inserta dentro de la base de datos. Otra vez, la diferencia entre save y create es que save acepta una instancia de modelo Eloquent completa mientras que create acepta un array de PHP plano:

$post = App\Post::find(1);

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

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

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

$post = App\Post::find(1);

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

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

Actualizar relación pertenece a (belongsTo)

Al momento de actualizar una relación belongsTo, puedes usar el método associate. Este método establecerá la clave foránea en el modelo hijo:

$account = App\Account::find(10);

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

$user->save();

Al momento de eliminar una relación belongsTo, puedes usar el método dissociate. Este método establecerá la clave foránea de la relación a null:

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

$user->save();

Modelos predeterminados

Las relaciones belongsTo, hasOne, hasOneThrough y morphOne te permiten definir un modelo predeterminado que se devolverá si la relación dada es null. A este patrón se le conoce comúnmente como patrón Null Object y puede ayudar a quitar comprobaciones condicionales en tu código. En el ejemplo siguiente, la relación user devolverá un modelo App\User vacío si no hay un user adjunto a la publicación:

/**
* Get the author of the post.
*/
public function user()
{
    return $this->belongsTo('App\User')->withDefault();
}

Para rellenar el modelo predeterminado con atributos, puedes pasar un arreglo o Closure al método withDefault:

/**
* Get the author of the post.
*/
public function user()
{
    return $this->belongsTo('App\User')->withDefault([
        'name' => 'Guest Author',
    ]);
}

/**
* Get the author of the post.
*/
public function user()
{
    return $this->belongsTo('App\User')->withDefault(function ($user, $post) {
        $user->name = 'Guest Author';
    });
}

Relaciones muchos a muchos

Adjuntando (attach) / Quitando (detach)

Eloquent también proporciona algunos métodos helper adicionales para hacer que el trabajo con los modelos relacionados sea más conveniente. Por ejemplo, vamos a imaginar que un usuario tiene muchos roles y un rol puede tener muchos usuarios. Para adjuntar un rol a un usuario insertando un registro en la tabla intermedia que vincula los modelos, usa el método attach:

$user = App\User::find(1);

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

Al momento de adjuntar una relación a un modelo, también puedes pasar un arreglo de datos adicionales para ser insertados dentro de la tabla intermedia:

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

Algunas veces puede ser necesario quitar un rol de un usuario. Para remover un registro de una relación de muchos-a-muchos, usa 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:

// Detach a single role from the user...
$user->roles()->detach($roleId);

// Detach all roles from the user...
$user->roles()->detach();

Por conveniencia, attach y detach también aceptan arreglos de IDs como entrada:

$user = App\User::find(1);

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

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

Sincronizando asociaciones

También puedes usar el método sync para construir asociaciones muchos-a-muchos. El método sync acepta un arreglo de IDs para colocar en la tabla intermedia. Algunos IDs que no estén en el arreglo dado serán removidos de la tabla intermedia. Por tanto, después que esta operación se complete, solamente los IDs en el arreglo dado existirán en la tabla intermedia:

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

También puedes pasar valores adicionales de tabla intermedia con los IDs:

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

Si no quieres quitar los IDs existentes, puedes usar el método syncWithoutDetaching:

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

Alternar asociaciones

La relación de muchos-a-muchos también proporciona un método toggle el cual «alterna» el estado adjunto de los IDs dados. Si el ID está actualmente adjuntado, será removido. De igual forma, si está actualmente removido, será adjuntado:

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

Guardando datos adicionales en una tabla pivote

Al momento de trabajar con una relación de muchos-a-muchos, el método save acepta un arreglo de atributos adicionales de tabla intermedia como su segundo argumento:

App\User::find(1)->roles()->save($role, ['expires' => $expires]);

Actualizando un registro en una tabla pivote

Si necesitas actualizar una fila existente en tu tabla pivote, puedes usar el método updateExistingPivot. Este método acepta la clave foránea del registro pivote y un arreglo de atributos para actualizar:

$user = App\User::find(1);

$user->roles()->updateExistingPivot($roleId, $attributes);

Tocando marcas de tiempo del padre

Cuando un modelo belongsTo o belongsToMany a otro modelo, tal como un Comment el cual pertenece a un Post, algunas veces es útil actualizar la marca de tiempo del padre cuando el modelo hijo es actualizado. Por ejemplo, cuando un modelo Comment es actualizado, puedes querer «tocar» automáticamente la marca de tiempo updated_at del Post que lo posee. Eloquent hace esto fácil. Simplemente agrega una propiedad touches conteniendo los nombres de las relaciones al modelo hijo:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
    * All of the relationships to be touched.
    *
    * @var array
    */
    protected $touches = ['post'];

    /**
    * Get the post that the comment belongs to.
    */
    public function post()
    {
        return $this->belongsTo('App\Post');
    }
}

Ahora, cuando actualices un Comment, el Post que lo posee tendrá su columna updated_at actualizada también, haciéndolo más conveniente para saber cuándo invalidar una caché del modelo Post:

$comment = App\Comment::find(1);

$comment->text = 'Edit to this comment!';

$comment->save();

Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.

Lección anterior Eloquent: Primeros Pasos - Documentación de Laravel 6 Lección siguiente Eloquent: Colecciones - Documentación de Laravel 6