> 백엔드 개발 > PHP 튜토리얼 > Laravel 프레임워크 - EloquentORM의 고급 부분에 대한 자세한 소개

Laravel 프레임워크 - EloquentORM의 고급 부분에 대한 자세한 소개

黄舟
풀어 주다: 2023-03-06 19:32:01
원래의
1666명이 탐색했습니다.

연관

일대일
사용자모델이 전화 모델과 연관되어 있다고 가정합니다. 이러한 연관을 정의하려면 사용자에서 전화 방법을 정의해야 합니다. 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;);
    }
}
로그인 후 복사

에 의해 정의된 연관을 반환하는 모델 hasOne 메소드의 첫 번째 매개변수는 연관될 모델입니다. 정의된 후 다음 구문을 사용하여 연관 속성을 쿼리할 수 있습니다. >

$phone = User::find(1)->phone;
로그인 후 복사

Eloquent는 외래 키가 모델 이름을 기반으로 연관되어 있다고 가정하므로 전화 모델은 자동으로 user_id 필드를 외래 키로 사용하며 이는 두 번째 및 세 번째 매개변수를 사용하여 재정의할 수 있습니다

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;);
로그인 후 복사

역관계 정의

위 모델을 정의한 후 User 모델을 사용하여 Phone 모델을 얻을 수 있습니다. 물론, Phone 모델을 통해서도 해당 User를 얻을 수 있습니다.

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

    }
}
로그인 후 복사

일대다

관련 댓글 정보가 많은 게시물이 있다고 가정해 보겠습니다. 이 경우에는 일대다 연결을 사용해야 합니다. 🎜>
<?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;);
    }
}
로그인 후 복사

역방향 연관을 정의하기 위한

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

$comments = App\Post::find(1)->comments()->where(&#39;title&#39;, &#39;foo&#39;)->first();
로그인 후 복사

쿼리 작업

역방향 연관도 ownTo 메소드를 사용합니다. 일대일 섹션을 참조하세요.

$comment = App\Comment::find(1);
echo $comment->post->title;
로그인 후 복사

다대다

다대다 연결은 추가 중간 테이블이 있기 때문에 hasOne 및 hasMany보다 구현하기가 더 복잡합니다.

사용자가 여러 역할에 속할 수 있고 역할도 여러 사용자에 속할 수 있는 시나리오를 생각해 보세요. 여기에는 users,roles,role_user라는 세 가지 테이블이 소개됩니다. role_user 테이블은 관련 테이블이며 user_id와 role_id라는 두 개의 필드를 포함합니다.

다대다 연결에는 presentsToMany 메소드가 필요합니다

<?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;);
    }
}
로그인 후 복사

위에서는 사용자가 여러 역할에 속해 있음을 정의합니다. 일단 관계가 설정되면

user = App\User::find(1);
foreach ($user->roles as $role) {    //}$roles = App\User::find(1)->roles()->orderBy(&#39;name&#39;)->get();
로그인 후 복사

를 쿼리할 수 있습니다. 역방향 연관 관계

역방향 관계는 순방향 관계와 동일하게 구현

<?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;);
    }
}
로그인 후 복사

중간 테이블의 열 값 검색

다대다 관계의 경우 중간 테이블이 도입되었기 때문에 관계가 성립된 시간 등 중간 테이블의 컬럼 값을 조회할 수 있는 방법이 필요합니다. 피벗 속성을 사용하여 중간 테이블을 조회

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

foreach ($user->roles as $role) {
    echo $role->pivot->created_at;
}
로그인 후 복사

위 코드는 중간 테이블의 Created_at 필드에 액세스합니다.

기본적으로 피벗

객체

를 통해 모델의 키에 액세스할 수 있습니다. 중간 테이블에 추가 속성이 포함되어 있으면 연결을 지정할 때 withPivot 메서드를 사용해야 합니다. 열 이름

Has Many Through

를 명시적으로 지정합니다. 이 관계는 상대적으로 강력합니다. 다음과 같은 시나리오가 있다고 가정합니다. 국가 모델에 여러 사용자 모델이 포함되어 있고 각 사용자 모델에 다중 게시물 모델이 포함되어 있습니다. 즉, 한 국가에 많은 사용자가 있고 이 사용자가 특정 국가의 모든 게시물을 쿼리하려고 합니다. 이를 달성하는 방법은 Has Many Through 관계를 사용하는 것입니다

countries    id - integer
    name - stringusers    id - integer
    country_id - integer
    name - stringposts    id - integer
    user_id - integer
    title - string
로그인 후 복사

보시다시피, 게시물 테이블에는 country_id가 직접 포함되어 있지 않지만, users 테이블을 통해 국가 테이블과 관계가 설정됩니다

Has Many Through 관계 사용

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;);
    }
}
로그인 후 복사

의 첫 번째 매개변수는 hasManyThrough 메소드는 액세스하려는 모델의 이름이고 두 번째 매개변수는 중간 모델 이름입니다.

HasManyThrough hasManyThrough( 
    string $related, 
    string $through, 
    string|null $firstKey = null, 
    string|null $secondKey = null, 
    string|null $localKey = null)
로그인 후 복사

다형성 관계(다형성 연관)

다형성 관계를 사용하면 하나의 연관을 사용하여 동일한 모델이 여러 다른 모델에 속할 수 있습니다. 이러한 시나리오를 가정하면 포스트 테이블과 코멘트 테이블이 있습니다. , 사용자는 게시물과 댓글을 모두 좋아할 수 있습니다. 이 상황을 처리하는 방법은 무엇입니까?

테이블 구조는 다음과 같습니다

posts    id - integer
    title - string
    body - textcomments    id - integer
    post_id - integer
    body - textlikes    id - integer
    likeable_id - integer
    likeable_type - string
로그인 후 복사

보시는 바와 같이 likes 테이블의 likeable_type 필드를 사용하여 해당 레코드가 게시물을 좋아하는지 댓글을 좋아하는지 확인합니다.

<?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;);
    }
}
로그인 후 복사

기본적으로 likeable_type 유형은 AppPost 및 AppComment와 같은 관련 모델의 전체 이름입니다.

일반적으로 사용자 정의 값을 사용하여 연관된 테이블 이름을 식별할 수 있으므로 이 값을 사용자 정의해야 합니다. 예를 들어 프로젝트 서비스 제공자 객체의 부팅 메소드에 연결을 등록해야 합니다. ,

의 부팅 방법에서

use Illuminate\Database\Eloquent\Relations\Relation;Relation::morphMap([    &#39;posts&#39; => App\Post::class,
    &#39;likes&#39; => App\Like::class,]);
로그인 후 복사
AppServiceProvider는 다형성 관계를 검색합니다.

는 게시물의 모든 좋아요에 액세스합니다.

$post = App\Post::find(1);  
foreach ($post->likes as $like) {    //}
로그인 후 복사

는 좋아요를 누른 게시물이나 댓글에 액세스합니다.

$like = App\Like::find(1);   
$likeable = $like->likeable;
로그인 후 복사

위 예에서 반환된 likeable은 레코드 유형에 따라 게시물이나 댓글을 반환합니다.

다대다 다형성 연관

다대다 연관은 morphToMany 및 morphedByMany 메소드를 사용합니다. 여기서는 더 이상 말도 안 됩니다

연관 관계 쿼리

Eloquent에서 모든 관계는

관련 쿼리를 실행하지 않고도 관련 인스턴스를 얻을 수 있는

함수를 사용하여 정의됩니다. 블로그 시스템이 있고 User 모델이 많은 Post 모델과 연결되어 있다고 가정합니다.

다음과 같이 연결을 쿼리하고

제약 조건

를 추가할 수 있습니다. 필요하지 않음 모델의 속성으로 직접 액세스할 수 있는 관련 속성에 제약 조건을 추가합니다. 예를 들어 위의 예에서는 다음 방법을 사용하여 사용자 게시물에 액세스할 수 있습니다

$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();
로그인 후 복사

위 내용은 Laravel 프레임워크 - EloquentORM의 고급 부분에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿