Está en la página 1de 65

Eloquent: Relaciones

 Introducción
 Definición de relaciones
o Uno a uno
o Uno a muchos
o Uno a muchos (inverso)
o Muchos a muchos
o Definición de modelos personalizados de tablas intermedias
o Tiene uno a través
o Tiene muchos a través

 Relaciones polimórficas
o Uno a uno
o Uno a muchos
o Muchos a muchos
o Tipos polimórficos personalizados

 Relaciones dinámicas
 Consultar relaciones
o Métodos de relación vs. Propiedades dinámicas
o Consultar la existencia de la relación
o Consulta de ausencia de relación
o Consultar relaciones polimórficas
o Contando modelos relacionados
o Contando modelos relacionados en relaciones polimórficas

 Carga ansiosa
o Restricción de cargas impacientes
o Carga impaciente perezosa

 Insertar y actualizar modelos relacionados


o El savemétodo
o El createmétodo
o Pertenece a las relaciones
o Muchas a muchas relaciones

 Tocar las marcas de tiempo de los padres


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

 Uno a uno
 Uno a muchos
 Muchos a muchos
 Tiene uno a través
 Tiene muchos a través
 Uno a uno (polimórfico)
 Uno a muchos (polimórfico)
 Muchos a muchos (polimórfico)

Definición de relaciones
Las relaciones elocuentes se definen como métodos en sus clases modelo elocuentes. Dado que,
como los propios modelos de Eloquent, las relaciones también sirven como poderosos constructores
de consultas , definir las relaciones como métodos proporciona potentes capacidades de
encadenamiento de métodos y consultas. Por ejemplo, podemos encadenar restricciones adicionales
en esta postsrelación:

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

Pero, antes de sumergirnos demasiado en el uso de las relaciones, aprendamos a definir cada tipo.

Los nombres de las relaciones no pueden colisionar con los nombres de los atributos, ya que eso
podría hacer que su modelo no pueda saber cuál resolver.
Uno a uno

Una relación uno a uno es una relación muy básica. Por ejemplo, un Usermodelo puede estar
asociado con uno Phone. Para definir esta relación, colocamos un phonemétodo en
el Usermodelo. El phonemétodo debe llamar al hasOnemétodo 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 que se pasa al hasOnemétodo es el nombre del modelo relacionado. Una vez
que se define la relación, podemos recuperar el registro relacionado usando las propiedades
dinámicas de Eloquent. Las propiedades dinámicas le permiten acceder a métodos de relación como
si fueran propiedades definidas en el modelo:

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

Eloquent determina la clave externa de la relación en función del nombre del modelo. En este
caso, Phonese asume automáticamente que el modelo tiene una user_idclave externa. Si desea
anular esta convención, puede pasar un segundo argumento al hasOnemétodo:

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


Además, Eloquent asume que la clave externa debe tener un valor que coincida con la columna id(o
personalizada $primaryKey) del padre. En otras palabras, Eloquent buscará el valor de
la idcolumna del usuario en la user_idcolumna del Phoneregistro. Si desea que la relación utilice un
valor distinto de id, puede pasar un tercer argumento al hasOnemétodo que especifica su clave
personalizada:

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

Definiendo lo inverso de la relación

Entonces, podemos acceder al Phonemodelo desde nuestro User. Ahora, definamos una relación en


el Phonemodelo que nos permitirá acceder al Userpropietario del teléfono. Podemos definir la inversa
de una hasOnerelación usando el belongsTométodo:

<?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_iddel Phonemodelo con idel


del Usermodelo. Eloquent determina el nombre de clave externa predeterminado examinando el
nombre del método de relación y añadiendo el sufijo al nombre del método _id. Sin embargo, si la
clave externa en el Phone modelo no lo es user_id, puede pasar un nombre de clave personalizada
como segundo argumento del belongsTo método:

/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('App\User', 'foreign_key');
}
Si su modelo principal no lo utiliza idcomo clave principal, o si desea unir el modelo secundario a
una columna diferente, puede pasar un tercer argumento al belongsTométodo que especifica la clave
personalizada de su tabla principal:

/**
* 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 se utiliza para definir relaciones en las que un solo modelo posee
cualquier cantidad de otros modelos. Por ejemplo, una publicación de blog puede tener una cantidad
infinita de comentarios. Como todas las demás relaciones de Eloquent, las relaciones de uno a
muchos se definen colocando una función en su modelo de 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');
}
}

Recuerde, Eloquent determinará automáticamente la columna de clave externa adecuada en


el Commentmodelo. Por convención, Eloquent tomará el nombre de "caso de serpiente" del modelo
propietario y lo agregará como sufijo _id. Entonces, para este ejemplo, Eloquent asumirá que la
clave externa en el Commentmodelo es post_id.
Una vez definida la relación, podemos acceder a la colección de comentarios accediendo a
la commentspropiedad. Recuerde, dado que Eloquent proporciona "propiedades dinámicas", podemos
acceder a los métodos de relación como si estuvieran definidos como propiedades en el modelo:

$comments = App\Post::find(1)->comments;
foreach ($comments as $comment) {
//
}

Dado que todas las relaciones también sirven como constructores de consultas, puede agregar más
restricciones a las que se recuperan los comentarios llamando al commentsmétodo y continuando
encadenando condiciones en la consulta:

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

Al igual que el hasOnemétodo, también puede anular las claves locales y externas pasando
argumentos adicionales al hasManymétodo:

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

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

Uno a muchos (inverso)

Ahora que podemos acceder a todos los comentarios de una publicación, definamos una relación
para permitir que un comentario acceda a su publicación principal. Para definir la inversa de
una hasManyrelación, defina una función de relación en el modelo hijo que llama al belongsTométodo:

<?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 definida la relación, podemos recuperar el Postmodelo de a Commentaccediendo a


la post"propiedad dinámica":

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

echo $comment->post->title;

En el ejemplo anterior, Eloquent intentará hacer coincidir el post_iddel Commentmodelo con idel


del Postmodelo. Eloquent determina el nombre de la clave externa predeterminada examinando el
nombre del método de relación y agregando como sufijo el nombre del método _seguido del nombre
de la columna de la clave principal. Sin embargo, si la clave externa en el Commentmodelo no lo
es post_id, puede pasar un nombre de clave personalizada como segundo argumento
del belongsTométodo:

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

Si su modelo principal no lo utiliza idcomo clave principal, o si desea unir el modelo secundario a


una columna diferente, puede pasar un tercer argumento al belongsTométodo que especifica la clave
personalizada de su tabla principal:

/**
* 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 un poco más complicadas que


las relaciones hasOney 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 la
función de "administrador".

Estructura de la tabla

Para definir esta relación, se necesitan tres tablas de la base: users, roles,


y role_user. La role_usertabla se deriva del orden alfabético de los nombres de modelos
relacionados y contiene las columnas user_idy 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 varios a varios se definen escribiendo un método que devuelve el resultado
del belongsToManymétodo. Por ejemplo, definamos el rolesmétodo en nuestro Usermodelo:

<?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 definida la relación, puede acceder a los roles del usuario utilizando la rolespropiedad
dinámica:

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

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


//
}

Como todos los demás tipos de relaciones, puede llamar al rolesmétodo para continuar
encadenando restricciones de consulta a la relación:

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

Como se mencionó anteriormente, para determinar el nombre de la tabla de unión de la relación,


Eloquent unirá los dos nombres de modelos relacionados en orden alfabético. Sin embargo, puede
anular esta convención. Puede hacerlo pasando un segundo argumento al belongsToManymétodo:

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

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

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

Definiendo lo inverso de la relación

Para definir la inversa de una relación de varios a varios, realiza otra llamada a belongsToManyen su
modelo relacionado. Para continuar con nuestro ejemplo de roles de usuario, definamos
el usersmétodo en el Rolemodelo:

<?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 puede ver, la relación se define exactamente igual que su Usercontraparte, con la excepción
de hacer referencia al modelo. Dado que estamos reutilizando el método, todas las tablas habituales
y las opciones de personalización de claves están disponibles al definir la inversa de las relaciones
de muchos a muchos.App\UserbelongsToMany

Recuperar columnas de tabla intermedias

Como ya ha aprendido, trabajar con relaciones de varios a varios requiere la presencia de una tabla
intermedia. Eloquent proporciona algunas formas muy útiles de interactuar con esta mesa. Por
ejemplo, supongamos que nuestro Userobjeto tiene muchos Roleobjetos con los que está
relacionado. Luego de acceder a esta relación, podemos acceder a la tabla intermedia usando
el pivotatributo en los modelos:
$user = App\User::find(1);

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


echo $role->pivot->created_at;
}

Observe que a cada Rolemodelo que recuperamos se le asigna automáticamente


un pivotatributo. Este atributo contiene un modelo que representa la tabla intermedia y puede usarse
como cualquier otro modelo de Eloquent.

De forma predeterminada, solo las claves del modelo estarán presentes en el pivotobjeto. Si su
tabla dinámica contiene atributos adicionales, debe especificarlos al definir la relación:

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

Si desea que su tabla dinámica se mantenga


automáticamente created_aty tenga updated_atmarcas de tiempo, use el withTimestampsmétodo en
la definición de relación:

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

Personalización del pivotnombre del atributo

Como se señaló anteriormente, se puede acceder a los atributos de la tabla intermedia en los
modelos que utilizan el pivotatributo. Sin embargo, puede 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 de varios a varios entre los usuarios y los podcasts. Si este es el caso, es posible
que desee cambiar el nombre de su descriptor de acceso a la tabla intermedia a
en subscriptionlugar de pivot. Esto se puede hacer usando el asmétodo al definir la relación:

return $this->belongsToMany('App\Podcast')

->as('subscription')
->withTimestamps();

Una vez hecho esto, 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;

Filtrar relaciones a través de columnas de tabla intermedias

También puede filtrar los resultados devueltos por belongsToManyel uso de


la wherePivot, wherePivotIny wherePivotNotInmétodos en la definición de 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]);

Definición de modelos personalizados de tablas intermedias

Si desea definir un modelo personalizado para representar la tabla intermedia de su relación, puede
llamar al usingmétodo al definir la relación. Los modelos dinámicos personalizados de muchos a
muchos deben extender la clase, mientras que los modelos dinámicos polimórficos personalizados
de muchos a muchos deben extender la clase. Por ejemplo, podemos definir un que usa un modelo
de
pivote personalizado :Illuminate\Database\Eloquent\Relations\PivotIlluminate\Database\Eloquent\Relati
ons\MorphPivotRoleRoleUser

<?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 definir el RoleUsermodelo, ampliaremos la Pivotclase:

<?php

namespace App;

use Illuminate\Database\Eloquent\Relations\Pivot;

class RoleUser extends Pivot

//

}
Puede combinar usingy withPivotpara recuperar columnas de la tabla intermedia. Por ejemplo,
puede recuperar las columnas created_byy updated_byde la RoleUsertabla dinámica pasando los
nombres de las columnas al withPivotmétodo:

<?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: Es posible que los modelos pivote no utilicen el SoftDeletesrasgo. Si necesita eliminar
temporalmente los registros de pivote, considere convertir su modelo de pivote en un modelo de
Eloquent real.

Modelos dinámicos personalizados e ID en aumento

Si ha definido una relación de muchos a muchos que usa un modelo de pivote personalizado, y ese
modelo de pivote tiene una clave principal que se incrementa automáticamente, debe asegurarse de
que su clase de modelo de pivote personalizado defina una incrementingpropiedad configurada
en true.

/**

* Indicates if the IDs are auto-incrementing.

* @var bool

*/

public $incrementing = true;

Tiene uno a través

La relación "tiene uno a través" vincula los modelos a través de una única relación intermedia.

Por ejemplo, en una aplicación de taller de reparación de vehículos, cada uno Mechanicpuede tener
uno Cary cada uno Carpuede tener uno Owner. Si bien el Mechanicy el Ownerno tienen conexión
directa, el Mechanicpuede acceder a Owner través del Carmismo. 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 la tabla para la relación, definamos la relación en
el Mechanicmodelo:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
class Mechanic extends Model

/**

* Get the car's owner.

*/

public function carOwner()

return $this->hasOneThrough('App\Owner', 'App\Car');

El primer argumento que se pasa al hasOneThroughmétodo es el nombre del modelo final al que
deseamos acceder, mientras que el segundo argumento es el nombre del modelo intermedio.

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 tercer y cuarto
argumento al hasOneThroughmétodo. El tercer argumento es el nombre de la clave externa en el
modelo intermedio. El cuarto argumento es el nombre de la clave externa 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

/**

* Get the car's owner.


*/

public function carOwner()

return $this->hasOneThrough(

'App\Owner',

'App\Car',

'mechanic_id', // Foreign key on cars table...

'car_id', // Foreign key on owners table...

'id', // Local key on mechanics table...

'id' // Local key on cars table...

);

Tiene muchos a través

La relación "tiene-muchos-a través" proporciona un atajo conveniente para acceder a relaciones


distantes a través de una relación intermedia. Por ejemplo, un Countrymodelo puede tener
muchos Postmodelos a través de un Usermodelo intermedio . En este ejemplo, podría recopilar
fácilmente todas las publicaciones de blog de un país determinado. Veamos las tablas necesarias
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 postsno contiene una country_idcolumna, la hasManyThroughrelación proporciona acceso a


las publicaciones de un país a través de . Para realizar esta consulta, Eloquent inspecciona el en
la tabla intermedia . Después de encontrar los ID de usuario coincidentes, se utilizan para consultar
la tabla.$country->postscountry_idusersposts

Ahora que hemos examinado la estructura de la tabla para la relación, definámosla en


el Countrymodelo:

<?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 que se pasa al hasManyThroughmétodo es el nombre del modelo final al que
deseamos acceder, mientras que el segundo argumento es el nombre del modelo intermedio.

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 tercer y cuarto
argumento al hasManyThroughmétodo. El tercer argumento es el nombre de la clave externa en el
modelo intermedio. El cuarto argumento es el nombre de la clave externa en el modelo final. El
quinto argumento es la clave local, mientras que 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 de destino pertenezca a más de un tipo de modelo
utilizando una sola asociación.

Uno a uno (polimórfico)


Estructura de la tabla

Una relación polimórfica de uno a uno es similar a una relación simple de uno a uno; sin embargo, el
modelo de destino puede pertenecer a más de un tipo de modelo en una sola asociación. Por
ejemplo, un blog Posty un Userpueden compartir una relación polimórfica con un Imagemodelo. El
uso de una relación polimórfica uno a uno le permite tener una lista única de imágenes únicas que se
utilizan tanto para publicaciones de blog como para cuentas de usuario. 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

Tome nota de las columnas imageable_idy imageable_typede


la imagestabla. La imageable_idcolumna contendrá el valor de ID de la publicación o usuario,
mientras que la imageable_typecolumna contendrá el nombre de la clase del modelo
principal. La imageable_typecolumna se utiliza por elocuente para determinar qué "tipo" de modelo
padre a retorno cuando se accede a la imageablerelación.

Estructura del modelo

A continuación, examinemos las definiciones del 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');

Recuperando la relación

Una vez que la tabla y los modelos de su base de datos estén definidos, puede acceder a las
relaciones a través de sus modelos. Por ejemplo, para recuperar la imagen de una publicación,
podemos usar la imagepropiedad dinámica:

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

$image = $post->image;
También puede recuperar el padre del modelo polimórfico accediendo al nombre del método que
realiza la llamada a morphTo. En nuestro caso, ese es el imageablemétodo
del Imagemodelo. Entonces, accederemos a ese método como una propiedad dinámica:

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

$imageable = $image->imageable;

La imageablerelación del Imagemodelo devolverá una instancia Posto User, según el tipo de modelo


que posea la imagen. Si necesita especificar columnas personalizadas typey idpara
la morphTorelación, asegúrese siempre de pasar el nombre de la relación (que debe coincidir
exactamente con el nombre del método) como primer parámetro:

/**

* Get the model that the image belongs to.

*/

public function imageable()

return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');

Uno a muchos (polimórfico)


Estructura de la tabla

Una relación polimórfica de uno a muchos es similar a una relación simple de uno a muchos; sin
embargo, el modelo de destino puede pertenecer a más de un tipo de modelo en una sola
asociación. Por ejemplo, imagine que los usuarios de su aplicación pueden "comentar" tanto en
publicaciones como en videos. Usando relaciones polimórficas, puede usar una sola commentstabla
para ambos escenarios. 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 del modelo 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');

Recuperando la relación

Una vez que la tabla y los modelos de su base de datos estén definidos, puede acceder a las
relaciones a través de sus modelos. Por ejemplo, para acceder a todos los comentarios de una
publicación, podemos usar la commentspropiedad dinámica:

$post = App\Post::find(1);
foreach ($post->comments as $comment) {

//

También puede recuperar el propietario de una relación polimórfica del modelo polimórfico
accediendo al nombre del método que realiza la llamada a morphTo. En nuestro caso, ese es
el commentablemétodo del Commentmodelo. Entonces, accederemos a ese método como una
propiedad dinámica:

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

$commentable = $comment->commentable;

La commentablerelación en el Commentmodelo devolverá una instancia Posto Video, según el tipo de


modelo que posea el comentario.

Muchos a muchos (polimórfico)


Estructura de la tabla

Las relaciones polimórficas de muchos a muchos son un poco más complicadas que
las relaciones morphOney morphMany. Por ejemplo, un blog Posty un Videomodelo podrían compartir
una relación polimórfica con un Tagmodelo. El uso de una relación polimórfica de muchos a muchos
le permite tener una sola lista de etiquetas únicas que se comparten entre publicaciones de blog y
videos. Primero, examinemos la estructura de la 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

A continuación, estamos listos para definir las relaciones en el


modelo. Los modelos Posty Videotendrán un tagsmétodo que llama al morphToManymétodo en la
clase base 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 lo inverso de la relación

A continuación, en el Tagmodelo, debe definir un método para cada uno de sus modelos
relacionados. Entonces, para este ejemplo, definiremos un postsmétodo y un videosmétodo:

<?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');

Recuperando la relación

Una vez que la tabla y los modelos de su base de datos estén definidos, puede acceder a las
relaciones a través de sus modelos. Por ejemplo, para acceder a todas las etiquetas de una
publicación, puede usar la tagspropiedad dinámica:
$post = App\Post::find(1);

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

//

También puede recuperar el propietario de una relación polimórfica del modelo polimórfico
accediendo al nombre del método que realiza la llamada a morphedByMany. En nuestro caso, esos
son los métodos postso videosen el Tagmodelo. Entonces, accederá a esos métodos como
propiedades dinámicas:

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

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

//

Tipos polimórficos personalizados

De forma predeterminada, Laravel usará el nombre de clase completamente calificado para


almacenar el tipo del modelo relacionado. Por ejemplo, dado el ejemplo de uno a muchos anterior,
donde a Commentpuede pertenecer a a Posto a Video, el valor
predeterminado commentable_typesería o , respectivamente. Sin embargo, es posible que desee
desacoplar su base de datos de la estructura interna de su aplicación. En ese caso, puede definir un
"mapa de transformación" para indicarle a Eloquent que use un nombre personalizado para cada
modelo en lugar del nombre de la clase:App\PostApp\Video

use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([

'posts' => 'App\Post',

'videos' => 'App\Video',

]);

Puede registrar el morphMapen la bootfunción de su AppServiceProvidero crear un proveedor de


servicios separado si lo desea.

Al agregar un "mapa de transformación" a su aplicación existente, cada *_typevalor de


columna modificable en su base de datos que aún contiene una clase totalmente calificada deberá
convertirse a su nombre de "mapa".

Puede determinar el alias de transformación de un modelo dado en tiempo de ejecución utilizando


el getMorphClassmétodo. Por el contrario, puede determinar el nombre de clase completamente
calificado asociado con un alias de morph usando el método:Relation::getMorphedModel

use Illuminate\Database\Eloquent\Relations\Relation;

$alias = $post->getMorphClass();

$class = Relation::getMorphedModel($alias);

Relaciones dinámicas

Puede utilizar el resolveRelationUsingmétodo para definir relaciones entre modelos Eloquent en


tiempo de ejecución. Aunque normalmente no se recomienda para el desarrollo normal de
aplicaciones, en ocasiones esto puede ser útil al desarrollar paquetes de Laravel:

use App\Order;
use App\Customer;

Order::resolveRelationUsing('customer', function ($orderModel) {

return $orderModel->belongsTo(Customer::class, 'customer_id');

});

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

Consultar relaciones
Since all types of Eloquent relationships are defined via methods, you may call those methods to
obtain an instance of the relationship without actually executing the relationship queries. In addition,
all types of Eloquent relationships also serve as query builders, allowing you to continue to chain
constraints onto the relationship query before finally executing the SQL against your database.

For example, imagine a blog system in which a User model has many associated Post models:

<?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');

You may query the posts relationship and add additional constraints to the relationship like so:

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

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

Puede utilizar cualquiera de los métodos del generador de consultas en la relación, así que


asegúrese de explorar la documentación del generador de consultas para conocer todos los métodos
que están disponibles para usted.

Encadenamiento de orWherecláusulas después de las relaciones

Como se demostró en el ejemplo anterior, puede agregar restricciones adicionales a las relaciones
cuando las consulte. Sin embargo, tenga cuidado al encadenar orWherecláusulas en una relación, ya
que las orWherecláusulas 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();

// select * from posts

// where user_id = ? and active = 1 or votes >= 100

En la mayoría de las situaciones, es probable que desee utilizar grupos de restricciones para agrupar


lógicamente las verificaciones 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 necesita agregar restricciones adicionales a una consulta de relación de Eloquent, puede


acceder a la relación como si fuera una propiedad. Por ejemplo, si continuamos usando
nuestros modelos Usery de Postejemplo, podemos acceder a todas las publicaciones de un usuario
así:

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

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

//

Las propiedades dinámicas son de "carga diferida", lo que significa que solo cargarán sus datos de
relación cuando realmente acceda a ellas. Debido a esto, los desarrolladores a menudo usan
la carga ansiosa para precargar las relaciones que saben que se accederán después de cargar el
modelo. La carga ansiosa proporciona una reducción significativa en las consultas SQL que deben
ejecutarse para cargar las relaciones de un modelo.

Consultar la existencia de la relación

Al acceder a los registros de un modelo, es posible que desee limitar sus resultados en función de la
existencia de una relación. Por ejemplo, imagine que desea recuperar todas las publicaciones de
blog que tengan al menos un comentario. Para hacerlo, puede pasar el nombre de la relación a
los métodos hasy orHas:

// Retrieve all posts that have at least one comment...

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

También puede especificar un operador y contar 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 hasdeclaraciones anidadas también se pueden construir usando la notación de "puntos". Por
ejemplo, puede recuperar todas las publicaciones que tengan al menos un comentario y votar:

// Retrieve posts that have at least one comment with votes...

$posts = App\Post::has('comments.votes')->get();

Si necesita aún más potencia, puede utilizar los métodos whereHasy orWhereHaspara poner


condiciones "dónde" en sus hasconsultas. Estos métodos le permiten agregar restricciones
personalizadas a una restricción de relación, 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();

Consulta de ausencia de relación

Al acceder a los registros de un modelo, es posible que desee limitar sus resultados en función de la
ausencia de una relación. Por ejemplo, imagina que quieres recuperar todas las publicaciones de
blog que no tienen comentarios. Para hacerlo, puede pasar el nombre de la relación a
los métodos doesntHavey orDoesntHave:

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

Si necesita aún más potencia, puede utilizar los métodos whereDoesntHavey orWhereDoesntHavepara


poner condiciones "dónde" en sus doesntHaveconsultas. Estos métodos le permiten agregar
restricciones personalizadas a una restricción de relación, 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();

Puede utilizar la notación de "puntos" para ejecutar una consulta en una relación anidada. Por
ejemplo, la siguiente consulta recuperará todas las publicaciones que no tienen comentarios y las
publicaciones que tienen comentarios de autores que no están prohibidos:

use Illuminate\Database\Eloquent\Builder;

$posts = App\Post::whereDoesntHave('comments.author', function (Builder $query) {

$query->where('banned', 0);

})->get();

Consultar relaciones polimórficas


Para consultar la existencia de MorphTorelaciones, puede utilizar el whereHasMorphmétodo 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();
Puede usar el $typeparámetro para agregar diferentes restricciones según el 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 una serie de posibles modelos polimórficos, puede proporcionar *como comodín y
dejar que Laravel recupere todos los posibles tipos polimórficos de la base de datos. Laravel
ejecutará una consulta adicional para 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 desea contar el número de resultados de una relación sin cargarlos realmente, puede usar
el withCountmétodo, que colocará una columna en sus modelos resultantes. Por ejemplo:
{relation}_count

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

foreach ($posts as $post) {

echo $post->comments_count;

Puede agregar los "recuentos" para varias relaciones, así como 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 puede aplicar un alias al resultado del recuento de relaciones, lo que permite varios
recuentos 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á combinando withCountcon una selectdeclaración, asegúrese de llamar withCountdespués


del selectmétodo:

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

echo $posts[0]->title;

echo $posts[0]->body;

echo $posts[0]->comments_count;
Además, con el loadCountmétodo, puede cargar un recuento de relaciones después de que el
modelo principal ya se haya recuperado:

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

$book->loadCount('genres');

Si necesita establecer restricciones de consulta adicionales en la consulta de carga ansiosa, puede


pasar una matriz codificada por las relaciones que desea cargar. Los valores de la matriz deben
ser Closureinstancias que reciban la instancia del generador de consultas:

$book->loadCount(['reviews' => function ($query) {

$query->where('rating', 5);

}])

Contando modelos relacionados en relaciones polimórficas

Si desea cargar ansiosamente una morphTorelación, así como los recuentos de relaciones anidadas
en las diversas entidades que pueden ser devueltas por esa relación, puede usar el withmétodo en
combinación con el método de la morphTorelación morphWithCount.

En este ejemplo, asumamos Photoy Postmodelos pueden crear ActivityFeedmodelos. Además,


supongamos que los Photomodelos están asociados con Tagmodelos y los Postmodelos están
asociados con Commentmodelos.

Usando estas definiciones y relaciones de modelos, podemos recuperar ActivityFeedinstancias


de parentablemodelos y cargar ansiosamente todos los modelos y sus respectivos recuentos de
relaciones anidadas:

use Illuminate\Database\Eloquent\Relations\MorphTo;
$activities = ActivityFeed::query()

->with(['parentable' => function (MorphTo $morphTo) {

$morphTo->morphWithCount([

Photo::class => ['tags'],

Post::class => ['comments'],

]);

}])->get();

Además, puede usar el loadMorphCountmétodo para cargar ansiosamente todos los recuentos de
relaciones anidadas en las diversas entidades de la relación polimórfica si los ActivityFeedmodelos
ya se han recuperado:

$activities = ActivityFeed::with('parentable')

->get()

->loadMorphCount('parentable', [

Photo::class => ['tags'],

Post::class => ['comments'],

]);

Carga ansiosa
Al acceder a las relaciones de Eloquent como propiedades, los datos de la relación se "cargan de
forma diferida". 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 "cargar ansiosamente" las relaciones
en el momento en que consulta el modelo principal. La carga ansiosa alivia el problema de las
consultas N + 1. Para ilustrar el problema de la consulta N + 1, considere un Bookmodelo relacionado
con 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, recuperemos todos los libros y sus autores:

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

foreach ($books as $book) {


echo $book->author->name;

Este ciclo ejecutará 1 consulta para recuperar todos los libros de la mesa, luego otra consulta para
cada libro para recuperar el autor. Entonces, si tenemos 25 libros, este ciclo ejecutaría 26 consultas:
1 para el libro original y 25 consultas adicionales para recuperar el autor de cada libro.

Thankfully, we can use eager loading to reduce this operation to just 2 queries. When querying, you
may specify which relationships should be eager loaded using the with method:

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

foreach ($books as $book) {

echo $book->author->name;

For this operation, only two queries will be executed:

select * from books

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

Eager Loading Multiple Relationships

Sometimes you may need to eager load several different relationships in a single operation. To do so,
just pass additional arguments to the with method:

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

Nested Eager Loading


To eager load nested relationships, you may use "dot" syntax. For example, let's eager load all of the
book's authors and all of the author's personal contacts in one Eloquent statement:

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

Nested Eager Loading morphTo Relationships

Si desea cargar ansiosamente una morphTorelación, así como relaciones anidadas en las diversas
entidades que pueden ser devueltas por esa relación, puede usar el withmétodo en combinación con
el método de la morphTorelación morphWith. 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, vamos a suponer Event, Photoy Postmodelos pueden
crear ActivityFeedmodelos. Además, supongamos que los Eventmodelos pertenecen a
un Calendarmodelo, los Photomodelos están asociados con Tagmodelos y los Postmodelos
pertenecen a un Authormodelo.

Usando estas definiciones y relaciones de modelos, podemos recuperar ActivityFeedinstancias


de parentablemodelos y cargar ansiosamente todos los modelos 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();

Carga ansiosa de columnas específicas

Es posible que no siempre necesite todas las columnas de las relaciones que está recuperando. Por
esta razón, Eloquent te permite especificar qué columnas de la relación te gustaría recuperar:

$books = App\Book::with('author:id,name')->get();
Al usar esta función, siempre debe incluir la idcolumna y cualquier columna de clave externa
relevante en la lista de columnas que desea recuperar.
Carga ansiosa por defecto

A veces, es posible que desee cargar siempre algunas relaciones al recuperar un modelo. Para
lograr esto, puede definir una $withpropiedad 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 desea eliminar un elemento de la $withpropiedad para una sola consulta, puede usar
el withoutmétodo:

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

Restricción de cargas impacientes

A veces es posible que desee cargar una relación, pero también especificar condiciones de consulta
adicionales para la consulta de carga ansiosa. He aquí un ejemplo:

$users = App\User::with(['posts' => function ($query) {

$query->where('title', 'like', '%first%');

}])->get();

En este ejemplo, Eloquent solo cargará con entusiasmo publicaciones donde la titlecolumna de la
publicación contenga la palabra first. Puede llamar a otros métodos de creación de consultas para
personalizar aún más la operación de carga ansiosa:

$users = App\User::with(['posts' => function ($query) {

$query->orderBy('created_at', 'desc');
}])->get();

Es posible que los métodos limity el takegenerador de consultas no se utilicen al restringir cargas


impacientes.

Carga impaciente perezosa

A veces, es posible que deba cargar una relación con entusiasmo después de que el modelo
principal ya se haya recuperado. Por ejemplo, esto puede ser útil si necesita decidir dinámicamente
si cargar modelos relacionados:

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

if ($someCondition) {

$books->load('author', 'publisher');

Si necesita establecer restricciones de consulta adicionales en la consulta de carga ansiosa, puede


pasar una matriz codificada por las relaciones que desea cargar. Los valores de la matriz deben
ser Closureinstancias que reciban la instancia de consulta:

$author->load(['books' => function ($query) {

$query->orderBy('published_date', 'asc');

}]);

Para cargar una relación solo cuando aún no se ha cargado, use el loadMissingmétodo:

public function format(Book $book)

{
$book->loadMissing('author');

return [

'name' => $book->name,

'author' => $book->author->name,

];

Carga ansiosa perezosa anidada y morphTo

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

Este método acepta el nombre de la morphTorelación como su primer argumento y una matriz 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, vamos a suponer Event, Photoy Postmodelos pueden


crear ActivityFeedmodelos. Además, supongamos que los Eventmodelos pertenecen a
un Calendarmodelo, los Photomodelos están asociados con Tagmodelos y los Postmodelos
pertenecen a un Authormodelo.

Usando estas definiciones y relaciones de modelos, podemos recuperar ActivityFeedinstancias


de parentablemodelos y cargar ansiosamente todos los modelos y sus respectivas relaciones
anidadas:

$activities = ActivityFeed::with('parentable')

->get()

->loadMorph('parentable', [

Event::class => ['calendar'],

Photo::class => ['tags'],

Post::class => ['author'],

]);

Insertar y actualizar modelos relacionados


El método de guardar
Eloquent proporciona métodos convenientes para agregar nuevos modelos a las relaciones. Por
ejemplo, quizás necesite insertar una nueva Commentpara un Postmodelo. En lugar de establecer
manualmente el post_idatributo en el Comment, puede insertar Commentdirectamente desde
el savemétodo de la relación :

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

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

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

Observe que no accedemos a la commentsrelación como una propiedad dinámica. En su lugar,


llamamos al commentsmétodo para obtener una instancia de la relación. El savemétodo agregará
automáticamente el post_idvalor apropiado al nuevo Commentmodelo.

Si necesita guardar varios modelos relacionados, puede usar el saveManymétodo:

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

$post->comments()->saveMany([

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

new App\Comment(['message' => 'Another comment.']),

]);

El savey saveManymétodos no va a añadir los nuevos modelos para cualquier relación en memoria


que ya están cargados en el modelo padre. Si planea acceder a la relación después de usar
los métodos saveo saveMany, es posible que desee usar el refreshmétodo para volver a cargar el
modelo y sus relaciones:

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

$post->refresh();

// All comments, including the newly saved comment...

$post->comments;

Guardar modelos y relaciones de forma recursiva

Si desea savesu modelo y todas sus relaciones asociadas, puede usar el pushmétodo:

$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 savey saveMany, también puede utilizar el createmétodo, que acepta una


matriz de atributos, crea un modelo y lo inserta en la base de datos. Nuevamente, la diferencia
entre savey createes que saveacepta una instancia de modelo Eloquent completa mientras
que createacepta un PHP simple array:

$post = App\Post::find(1);
$comment = $post->comments()->create([

'message' => 'A new comment.',

]);

Antes de utilizar el createmétodo, asegúrese de revisar la documentación sobre la asignación


masiva de atributos .

Puede utilizar el createManymétodo para crear varios modelos relacionados:

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

$post->comments()->createMany([

'message' => 'A new comment.',

],

'message' => 'Another new comment.',

],

]);

También puede utilizar los findOrNew, firstOrNew, firstOrCreatey updateOrCreatemétodos


para crear y actualizar los modelos de relaciones .

Pertenece a las relaciones


Al actualizar una belongsTorelación, puede utilizar el associatemétodo. Este método establecerá la
clave externa en el modelo secundario:

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

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

$user->save();

Al eliminar una belongsTorelación, puede utilizar el dissociatemétodo. Este método establecerá la


clave externa de la relación en null:

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

$user->save();

Modelos predeterminados

Los belongsTo, hasOne, hasOneThrough, y morphOnerelaciones permiten definir un modelo


predeterminado que será devuelto si la relación es dada null. Este patrón a menudo se conoce
como patrón de objeto nulo y puede ayudar a eliminar las verificaciones condicionales en su
código. En el siguiente ejemplo, la userrelación devolverá un modelo vacío si no se adjunta a la
publicación:App\Useruser

/**

* Get the author of the post.

*/

public function user()


{

return $this->belongsTo('App\User')->withDefault();

Para completar el modelo predeterminado con atributos, puede pasar una matriz o un cierre
al withDefaultmétodo:

/**

* 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';

});

Muchas a muchas relaciones


Adjuntar / Desmontar

Eloquent también proporciona algunos métodos auxiliares adicionales para hacer que trabajar con
modelos relacionados sea más conveniente. Por ejemplo, imaginemos que un usuario puede tener
muchos roles y un rol puede tener muchos usuarios. Para adjuntar un rol a un usuario insertando un
registro en la tabla intermedia que une los modelos, use el attachmétodo:

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

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

Al adjuntar una relación a un modelo, también puede pasar una matriz de datos adicionales para
insertarlos 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 de
varios a varios, utilice el detachmétodo. El detachmétodo 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();

Para mayor comodidad, attachy detachtambién acepta matrices de ID como entrada:

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

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

$user->roles()->attach([

1 => ['expires' => $expires],

2 => ['expires' => $expires],

]);

Asociaciones de sincronización

También puede utilizar el syncmétodo para construir asociaciones de varios a varios. El syncmétodo


acepta una matriz de ID para colocar en la tabla intermedia. Cualquier ID que no esté en la matriz
dada se eliminará de la tabla intermedia. Entonces, después de que se complete esta operación,
solo los ID en la matriz dada existirán en la tabla intermedia:

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

También puede pasar valores de tabla intermedios adicionales con los ID:

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

Si no desea desvincular las ID existentes, puede utilizar el syncWithoutDetachingmétodo:

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

Asociaciones de alternancia
La relación de muchos a muchos también proporciona un togglemétodo que "alterna" el estado de
adjunto de los ID dados. Si la identificación proporcionada está actualmente adjunta, se
desvinculará. Asimismo, si actualmente se encuentra desvinculado, se adjuntará:

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

Guardar datos adicionales en una tabla dinámica

Cuando se trabaja con una relación de muchos a muchos, el savemétodo acepta una matriz de
atributos de tabla intermedia adicionales como segundo argumento:

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

Actualizar un registro en una tabla dinámica

Si necesita actualizar una fila existente en su tabla dinámica, puede usar


el updateExistingPivotmétodo. Este método acepta la clave externa del registro dinámico y una
matriz de atributos para actualizar:

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

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

Tocar las marcas de tiempo de los padres


Cuando un modelo belongsTou belongsToManyotro modelo, como uno Commentque pertenece a
un Post, a veces es útil actualizar la marca de tiempo del padre cuando se actualiza el modelo
hijo. Por ejemplo, cuando Commentse actualiza un modelo, es posible que desee "tocar"
automáticamente la updated_atmarca de tiempo de la propiedad Post. Eloquent te lo pone
fácil. Simplemente agregue una touchespropiedad que contenga los nombres de las relaciones al
modelo secundario:

<?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 actualice a Comment, la propiedad Posttambién tendrá su updated_atcolumna
actualizada, lo que hace que sea más conveniente saber cuándo invalidar un caché del Postmodelo:

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

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

$comment->save();

También podría gustarte