Maison >développement back-end >tutoriel php >Framework Laravel - Introduction détaillée aux parties avancées d'EloquentORM

Framework Laravel - Introduction détaillée aux parties avancées d'EloquentORM

黄舟
黄舟original
2017-03-21 09:18:191634parcourir

Association

One To One
Supposons que le modèle User soit associé au modèle Phone Pour définir une telle association, vous devez définir une méthode phone dans l'utilisateur. model, qui renvoie Une association définie par la méthode hasOne

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * Get the phone record associated with the user.
     */
    public function phone()
    {
        return $this->hasOne(&#39;App\Phone&#39;);
    }
}

Le premier paramètre de la méthode hasOne est le modèle à associer. Une fois défini, vous pouvez utiliser la syntaxe suivante pour interroger les attributs de l'association.

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

Eloquent supposera que la clé étrangère associée est basée sur le nom du modèle, donc le modèle de téléphone utilisera automatiquement le champ user_id comme clé étrangère. Vous pouvez utiliser les deuxième et troisième paramètres pour remplacer <.>

return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;);return $this->hasOne(&#39;App\Phone&#39;, &#39;foreign_key&#39;, &#39;local_key&#39;);
pour définir la relation inverse

Après avoir défini le modèle ci-dessus, vous pouvez utiliser le modèle Utilisateur pour obtenir le modèle Téléphone. Bien entendu, vous pouvez également obtenir l'Utilisateur correspondant via le Téléphone. modèle. Cela utilise la méthode AppartientTo

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model{
    /**
     * Get the user that owns the phone.
     */
    public function user()
    {
        return $this->belongsTo(&#39;App\User&#39;);        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;);
        // return $this->belongsTo(&#39;App\User&#39;, &#39;foreign_key&#39;, &#39;other_key&#39;);

    }
}
One To Many

Supposons qu'il y ait une publication avec de nombreuses informations de commentaires associées. Dans ce cas, une association un-à-plusieurs devrait. être utilisé, en utilisant la méthode hasMany

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model{
    /**
     * Get the comments for the blog post.
     */
    public function comments()
    {
        return $this->hasMany(&#39;App\Comment&#39;);
    }
}
opération de requête

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

$comments = App\Post::find(1)->comments()->where(&#39;title&#39;, &#39;foo&#39;)->first();
Définir l'association inverse

L'association inverse utilise également la méthode appartientTo, reportez-vous au One To One section.

$comment = App\Comment::find(1);
echo $comment->post->title;
Many To Many

L'association plusieurs-à-plusieurs a une table intermédiaire supplémentaire, elle est donc plus compliquée à mettre en œuvre que hasOne et hasMany.

Considérez un scénario dans lequel un utilisateur peut appartenir à plusieurs rôles, et un rôle peut également appartenir à plusieurs utilisateurs. Cela introduit trois tables : utilisateurs, rôles, role_user. La table role_user est une table associée et contient deux champs user_id et role_id.

L'association plusieurs-à-plusieurs nécessite la méthode AppartientToMany

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model{
    /**
     * The roles that belong to the user.
     */
    public function roles()
    {
        // 指定关联表
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;);
        // 指定关联表,关联字段
        // return $this->belongsToMany(&#39;App\Role&#39;, &#39;role_user&#39;, &#39;user_id&#39;, &#39;role_id&#39;);

        return $this->belongsToMany(&#39;App\Role&#39;);
    }
}
Ce qui précède définit qu'un utilisateur appartient à plusieurs rôles. Une fois la relation établie, elle peut être interrogée

<.>

Relation d'association inverse
user = App\User::find(1);
foreach ($user->roles as $role) {    //}$roles = App\User::find(1)->roles()->orderBy(&#39;name&#39;)->get();

La relation inverse est implémentée de la même manière que la relation directe

Récupérer la valeur de la colonne de la table intermédiaire
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model{
    /**
     * The users that belong to the role.
     */
    public function users()
    {
        return $this->belongsToMany(&#39;App\User&#39;);
    }
}

Pour beaucoup -à plusieurs relations, introduire Une table intermédiaire est créée, il doit donc y avoir un moyen d'interroger les valeurs des colonnes de la table intermédiaire, comme l'heure à laquelle la relation a été établie, etc. Utilisez l'attribut pivot pour interroger la table intermédiaire

Le code ci-dessus accède au champ create_at de la table intermédiaire.
$user = App\User::find(1);

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

Notez que par défaut, les clés du modèle sont accessibles via l'objet pivot

Si la table intermédiaire contient des attributs supplémentaires, vous devez utiliser la méthode withPivot lors de la spécification de l'association. Spécifiez explicitement le nom de la colonne

Has Many Through
return $this->belongsToMany(&#39;App\Role&#39;)->withPivot(&#39;column1&#39;, &#39;column2&#39;);

Cette relation est relativement puissante Supposons qu'il existe un scénario : le modèle Country contient plusieurs modèles User et chaque modèle User en contient plusieurs. Modèles de publication, c'est-à-dire qu'il y a de nombreux utilisateurs dans un pays, et ces utilisateurs ont de nombreuses publications. Nous voulons interroger toutes les publications dans un certain pays. Comment y parvenir ? Cela utilise la relation Has Many Through

<.>

Comme vous pouvez le voir, la table posts ne contient pas directement country_id, mais elle établit une relation avec la table country via la table users

countries    id - integer
    name - stringusers    id - integer
    country_id - integer
    name - stringposts    id - integer
    user_id - integer
    title - string
Utilisation de la relation Has Many Through

méthode Le premier paramètre de hasManyThrough est le nom du modèle auquel nous souhaitons accéder, et le deuxième paramètre est le nom du modèle intermédiaire.

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(&#39;App\Post&#39;, &#39;App\User&#39;, &#39;country_id&#39;, &#39;user_id&#39;);

        return $this->hasManyThrough(&#39;App\Post&#39;, &#39;App\User&#39;);
    }
}

Relations polymorphes (association polymorphe)

HasManyThrough hasManyThrough( 
    string $related, 
    string $through, 
    string|null $firstKey = null, 
    string|null $secondKey = null, 
    string|null $localKey = null)
Les relations polymorphes permettent au même modèle d'appartenir à plusieurs modèles différents en utilisant une seule association. En supposant un tel scénario, nous avons une table de publication et un commentaire. Les utilisateurs peuvent aimer à la fois les publications et les commentaires. Comment gérer cette situation ?

La structure de la table est la suivante

Comme vous pouvez le voir, nous utilisons le champ likeable_type dans la table des likes pour déterminer si l'enregistrement aime une publication ou un commentaire. La structure de la table est en place, il est temps de la définir Modèle

posts    id - integer
    title - string
    body - textcomments    id - integer
    post_id - integer
    body - textlikes    id - integer
    likeable_id - integer
    likeable_type - string

Par défaut, le type de likeable_type est le nom complet du modèle associé, comme AppPost et AppComment ici.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Like extends Model{    /**
     * Get all of the owning likeable models.
     */
    public function likeable()
    {        return $this->morphTo();
    }
}class Post extends Model{    /**
     * Get all of the product&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}class Comment extends Model{    /**
     * Get all of the comment&#39;s likes.
     */
    public function likes()
    {        return $this->morphMany(&#39;App\Like&#39;, &#39;likeable&#39;);
    }
}
Normalement, nous pouvons utiliser une valeur personnalisée pour identifier le nom de la table associée. Nous devons donc personnaliser cette valeur, par exemple. , dans la méthode de démarrage de

,

AppServiceProvider récupère les relations polymorphes

use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([    &#39;posts&#39; => App\Post::class,
    &#39;likes&#39; => App\Like::class,]);
accède à tous les likes d'une publication

accède à une publication ou un commentaire aimé

$post = App\Post::find(1);  
foreach ($post->likes as $like) {    //}

Dans l'exemple ci-dessus, le like renvoyé renverra des publications ou des commentaires en fonction du type d'enregistrement.

$like = App\Like::find(1);   
$likeable = $like->likeable;
Association polymorphe plusieurs-à-plusieurs

L'association plusieurs-à-plusieurs utilise les méthodes morphToMany et morphedByMany, plus de bêtises ici

Requête de relation d'association

Dans Eloquent, toutes les relations sont

définies à l'aide de fonctions

, qui vous permettent d'obtenir des instances associées sans exécuter de requête associée. Supposons que nous ayons un système de blog et que le modèle User soit associé à de nombreux modèles Post :

Vous pouvez interroger l'association comme suit et ajouter des

contraintes supplémentaires
/**
 * Get all of the posts for the user.
 */public function posts()
{   return $this->hasMany(&#39;App\Post&#39;);
}

S'il n'est pas nécessaire d'ajouter des contraintes aux attributs associés, ils sont accessibles directement en tant qu'attributs du modèle. Par exemple, dans l'exemple ci-dessus, nous pouvons utiliser la méthode suivante pour accéder à la publication de l'utilisateur

.
$user = App\User::find(1);foreach ($user->posts as $post) {    //}

动态的属性都是延迟加载的,它们只有在被访问的时候才会去查询数据库,与之对应的是预加载,预加载可以使用关联查询出所有数据,减少执行sql的数量。

查询关系存在性

使用has方法可以基于关系的存在性返回结果

// 检索至少有一个评论的所有帖子...$posts = App\Post::has(&#39;comments&#39;)->get();
// Retrieve all posts that have three or more comments...$posts = Post::has(&#39;comments&#39;, &#39;>=&#39;, 3)->get();
// Retrieve all posts that have at least one comment with votes...$posts = Post::has(&#39;comments.votes&#39;)->get();

如果需要更加强大的功能,可以使用whereHas和orWhereHas方法,把where条件放到has语句中。

// 检索所有至少存在一个匹配foo%的评论的帖子$posts = Post::whereHas(&#39;comments&#39;, function ($query) {    
$query->where(&#39;content&#39;, &#39;like&#39;, &#39;foo%&#39;);
})->get();

预加载

在访问Eloquent模型的时候,默认情况下所有的关联关系都是延迟加载的,在使用的时候才会开始加载,这就造成了需要执行大量的sql的问题,使用预加载功能可以使用关联查询出所有结果

<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Book extends Model{
    /**
     * Get the author that wrote the book.
     */
    public function author()
    {
        return $this->belongsTo(&#39;App\Author&#39;);
    }
}

接下来我们检索所有的书和他们的作者

$books = App\Book::all();
foreach ($books as $book) {    
echo $book->author->name;
}

上面的查询将会执行一个查询查询出所有的书,然后在遍历的时候再执行N个查询查询出作者信息,显然这样做是非常低效的,幸好我们还有预加载功能,可以将这N+1个查询减少到2个查询,在查询的时候,可以使用with方法指定哪个关系需要预加载。

$books = App\Book::with(&#39;author&#39;)->get();
foreach ($books as $book) {
    echo $book->author->name;
}

对于该操作,会执行下列两个sql

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

预加载多个关系

$books = App\Book::with(&#39;author&#39;, &#39;publisher&#39;)->get();

嵌套的预加载

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

带约束的预加载

$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->where(&#39;title&#39;, &#39;like&#39;, &#39;%first%&#39;);
}])->get();$users = App\User::with([&#39;posts&#39; => function ($query) {
    $query->orderBy(&#39;created_at&#39;, &#39;desc&#39;);
}])->get();

延迟预加载#

有时候,在上级模型已经检索出来之后,可能会需要预加载关联数据,可以使用load方法

$books = App\Book::all();if ($someCondition) {    $books->load(&#39;author&#39;, &#39;publisher&#39;);
}$books->load([&#39;author&#39; => function ($query) {
    $query->orderBy(&#39;published_date&#39;, &#39;asc&#39;);
}]);

关联模型插入

save方法

保存单个关联模型

$comment = new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]);
$post = App\Post::find(1);$post->comments()->save($comment);

保存多个关联模型

$post = App\Post::find(1); 
$post->comments()->saveMany([    
new App\Comment([&#39;message&#39; => &#39;A new comment.&#39;]),    
new App\Comment([&#39;message&#39; => &#39;Another comment.&#39;]),
]);

save方法和多对多关联

多对多关联可以为save的第二个参数指定关联表中的属性

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

上述代码会更新中间表的expires字段。

create方法

使用create方法与save方法的不同在于它是使用数组的形式创建关联模型的

$post = App\Post::find(1);$comment = $post->comments()->create([
    &#39;message&#39; => &#39;A new comment.&#39;,]);

更新 “Belongs To” 关系

更新belongsTo关系的时候,可以使用associate方法,该方法会设置子模型的外键

$account = App\Account::find(10);
$user->account()->associate($account);
$user->save();

要移除belongsTo关系的话,使用dissociate方法

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

Many to Many 关系

中间表查询条件#

当查询时需要对使用中间表作为查询条件时,可以使用wherePivotwherePivotInorWherePivotorWherePivotIn添加查询条件。

$enterprise->with([&#39;favorites&#39; => function($query) {    
$query->wherePivot(&#39;enterprise_id&#39;, &#39;=&#39;, 12)->select(&#39;id&#39;);
}]);

Attaching / Detaching#

$user = App\User::find(1);
// 为用户添加角色
$user->roles()->attach($roleId);
// 为用户添加角色,更新中间表的expires字段
$user->roles()->attach($roleId, [&#39;expires&#39; => $expires]);
// 移除用户的单个角色
$user->roles()->detach($roleId);
// 移除用户的所有角色
$user->roles()->detach();

attach和detach方法支持数组参数,同时添加和移除多个

$user = App\User::find(1);
$user->roles()->detach([1, 2, 3]);
$user->roles()->attach([1 => [&#39;expires&#39; => $expires], 2, 3]);

更新中间表(关联表)字段

使用updateExistingPivot方法更新中间表

$user = App\User::find(1);$user->roles()->updateExistingPivot($roleId, $attributes);

同步中间表(同步关联关系)#

使用sync方法,可以指定两个模型之间只存在指定的关联关系

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

上述两个方法都会让用户只存在1,2,3三个角色,如果用户之前存在其他角色,则会被删除。

更新父模型的时间戳#

假设场景如下,我们为一个帖子增加了一个新的评论,我们希望这个时候帖子的更新时间会相应的改变,这种行为在Eloquent中是非常容易实现的。

在子模型中使用$touches属性实现该功能

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;class Comment extends Model{    /**
     * All of the relationships to be touched.
     *
     * @var array
     */
    protected $touches = [&#39;post&#39;];    /**
     * Get the post that the comment belongs to.
     */
    public function post()
    {        return $this->belongsTo(&#39;App\Post&#39;);
    }
}

现在,更新评论的时候,帖子的updated_at字段也会被更新

$comment = App\Comment::find(1);$comment->text = &#39;Edit to this comment!&#39;;$comment->save();

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn