Heim  >  Artikel  >  Backend-Entwicklung  >  Laravel-Framework – Detaillierte Einführung in die erweiterten Teile von EloquentORM

Laravel-Framework – Detaillierte Einführung in die erweiterten Teile von EloquentORM

黄舟
黄舟Original
2017-03-21 09:18:191577Durchsuche

Zuordnung

Eins zu Eins
Angenommen, das BenutzerModell ist mit dem Telefonmodell verknüpft. Um eine solche Zuordnung zu definieren, müssen Sie im Benutzer eine Telefonmethode definieren Modell, das eine durch die hasOne-Methode definierte Assoziation zurückgibt.

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

Der erste Parameter der hasOne-Methode ist das zuzuordnende Modell. Nachdem es definiert wurde, können Sie die folgende Syntax verwenden, um die Assoziationsattribute abzufragen

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

Eloquent geht davon aus, dass der zugehörige Fremdschlüssel auf dem Modellnamen basiert, sodass das Telefonmodell automatisch das Feld user_id als Fremdschlüssel verwendet. Sie können den zweiten und dritten Parameter zum Überschreiben verwenden 🎜>

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;);
um die umgekehrte Beziehung zu definieren

Nachdem Sie das obige Modell definiert haben, können Sie das Benutzermodell verwenden, um das Telefonmodell abzurufen. Natürlich können Sie den entsprechenden Benutzer auch über das Telefon abrufen Modell. Dies verwendet die Methode „Eins zu Viele“

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

    }
}
Angenommen, es gibt einen Beitrag mit vielen zugehörigen Kommentarinformationen. In diesem Fall sollte eine Eins-zu-Viele-Zuordnung vorliegen verwendet werden, unter Verwendung der hasMany-Methode

Abfrageoperation

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

Umgekehrte Zuordnung definieren

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

$comments = App\Post::find(1)->comments()->where(&#39;title&#39;, &#39;foo&#39;)->first();
Umgekehrte Zuordnung verwendet auch die „gehörtTo“-Methode, siehe One To One Abschnitt.

Many-to-Many

$comment = App\Comment::find(1);
echo $comment->post->title;
Many-to-many-Assoziation verfügt über eine zusätzliche Zwischentabelle und ist daher komplizierter zu implementieren als hasOne und hasMany.

Stellen Sie sich ein Szenario vor, in dem ein Benutzer mehreren Rollen angehören kann und eine Rolle auch mehreren Benutzern angehören kann. Dadurch werden drei Tabellen eingeführt: Benutzer, Rollen, Rollenbenutzer. Die Tabelle „role_user“ ist eine verwandte Tabelle und enthält zwei Felder „user_id“ und „role_id“.

Many-to-many-Zuordnung erfordert die Methode „gehörtToMany“

Das Obige definiert, dass ein Benutzer mehreren Rollen angehört. Sobald die Beziehung hergestellt ist, kann sie abgefragt werden

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

Umgekehrte Assoziationsbeziehung

user = App\User::find(1);
foreach ($user->roles as $role) {    //}$roles = App\User::find(1)->roles()->orderBy(&#39;name&#39;)->get();
Die umgekehrte Beziehung wird genauso implementiert wie die Vorwärtsbeziehung

Rufen Sie den Spaltenwert der Zwischentabelle ab

<?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;);
    }
}
Für viele -zu-viele-Beziehungen einführen Eine Zwischentabelle wird erstellt, daher muss eine Möglichkeit vorhanden sein, die Spaltenwerte der Zwischentabelle abzufragen, z. B. den Zeitpunkt, zu dem die Beziehung hergestellt wurde usw. Verwenden Sie zum Abfragen das Pivot-Attribut die Zwischentabelle

Der obige Code greift auf das Feld „created_at“ der Zwischentabelle zu.

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

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}
Beachten Sie, dass auf die Schlüssel des Modells standardmäßig über das Pivot

-Objekt zugegriffen werden kann

Wenn die Zwischentabelle zusätzliche Attribute enthält, müssen Sie beim Festlegen der Zuordnung die Methode withPivot verwenden. Geben Sie explizit den Spaltennamen an

Hats Many Through

return $this->belongsToMany(&#39;App\Role&#39;)->withPivot(&#39;column1&#39;, &#39;column2&#39;);
Diese Beziehung ist relativ leistungsfähig: Angenommen, es gibt ein Szenario: Das Ländermodell enthält mehrere Benutzermodelle, und jedes Benutzermodell enthält mehrere Post-Modelle, das heißt, es gibt viele Benutzer in einem Land, und diese Benutzer haben viele Posts in einem bestimmten Land. Wie kann dies mithilfe der Has Many Through-Beziehung erreicht werden? 🎜>

Wie Sie sehen können, enthält die Posts-Tabelle nicht direkt „country_id“, sondern stellt über die Benutzertabelle eine Beziehung zur Ländertabelle her

Verwendung der Beziehung „Hats Many Through“

countries    id - integer
    name - stringusers    id - integer
    country_id - integer
    name - stringposts    id - integer
    user_id - integer
    title - string

Methode Der erste Parameter von hasManyThrough ist der Name des Modells, auf das wir zugreifen möchten, und der zweite Parameter ist der Name des Zwischenmodells.

Polymorphe Beziehungen (polymorphe Assoziation)
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;);
    }
}

Polymorphe Beziehungen ermöglichen die Zugehörigkeit desselben Modells zu mehreren verschiedenen Modellen unter Verwendung einer Assoziation. Unter der Annahme eines solchen Szenarios haben wir eine Post-Tabelle und einen Kommentar Tabelle: Benutzer können sowohl Beiträge als auch Kommentare mit „Gefällt mir“ markieren.

HasManyThrough hasManyThrough( 
    string $related, 
    string $through, 
    string|null $firstKey = null, 
    string|null $secondKey = null, 
    string|null $localKey = null)
Die Tabellenstruktur ist wie folgt

Wie Sie sehen können, verwenden wir das Feld likeable_type in der Likes-Tabelle, um zu bestimmen, ob dem Datensatz ein Beitrag oder ein Kommentar gefällt Wenn die Tabellenstruktur vorhanden ist, ist es an der Zeit, sie zu definieren Modell

Standardmäßig ist der Typ von likeable_type der vollständige Name des zugehörigen Modells, wie hier AppPost und AppComment.
posts    id - integer
    title - string
    body - textcomments    id - integer
    post_id - integer
    body - textlikes    id - integer
    likeable_id - integer
    likeable_type - string

Normalerweise verwenden wir einen benutzerdefinierten Wert, um den zugehörigen Tabellennamen zu identifizieren. Daher müssen wir die Zuordnung beispielsweise in der Boot-Methode des Dienstanbieterobjekts registrieren , in der Boot-Methode von

,
<?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;);
    }
}

ruft polymorphe Beziehungen ab

AppServiceProvider greift auf alle „Gefällt mir“-Angaben eines Beitrags zu

use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([    &#39;posts&#39; => App\Post::class,
    &#39;likes&#39; => App\Like::class,]);

greift auf einen Beitrag oder Kommentar mit „Gefällt mir“ zu

Im obigen Beispiel gibt der zurückgegebene Likeable Beiträge oder Kommentare basierend auf dem Typ des Datensatzes zurück.
$post = App\Post::find(1);  
foreach ($post->likes as $like) {    //}

Many-to-many polymorphe Assoziation

$like = App\Like::find(1);   
$likeable = $like->likeable;
Many-to-many-Assoziation verwendet die Methoden morphToMany und morphedByMany, hier ist kein Unsinn mehr

Assoziationsbeziehungsabfrage

In Eloquent werden alle Beziehungen

mithilfe von Funktionen

definiert, die es Ihnen ermöglichen, verwandte Instanzen abzurufen, ohne eine verwandte Abfrage auszuführen. Angenommen, wir haben ein Blog-System und das Benutzermodell ist mit vielen Post-Modellen verknüpft:

Sie können die Zuordnung wie folgt abfragen und zusätzliche Einschränkungen

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

Wenn den zugehörigen Attributen keine Einschränkungen hinzugefügt werden müssen, kann auf sie direkt als Attribute des Modells zugegriffen werden. Im obigen Beispiel können wir beispielsweise die folgende Methode verwenden, um auf den Benutzerbeitrag zuzugreifen

$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();

Das obige ist der detaillierte Inhalt vonLaravel-Framework – Detaillierte Einführung in die erweiterten Teile von EloquentORM. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn