모델 협회


ㅋㅋ +
역방향 연관 정의

Eloquent: 연관

상위 세트 타임스탬프 업데이트

다대- 다수(다형성 연관)

🎜 🎜🎜🎜🎜

Define Associations

Eloquent 연관은 Eloquent 모델 클래스의 메서드로 제공됩니다. Eloquent 모델 자체와 마찬가지로 연관은 강력한 체인 호출 및 쿼리 기능을 제공하는 강력한 쿼리 문 작성기로 사용될 수도 있습니다. 예를 들어 posts 연결에 대한 호출 체인에 제약 조건을 연결할 수 있습니다. posts 关联的链式调用中附加一个约束条件:

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

不过在深入使用关联之前,让我们先学习如何定义每种关联类型。

一对一

一对一是最基本的关联关系。例如,一个 User 模型可能关联一个 Phone 模型。为了定义这个关联,我们要在 User 模型中写一个 phone 方法。在 phone 方法内部调用 hasOne 方法并返回其结果:

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

hasOne 方法的第一个参数是关联模型的类名。一旦定义了模型关联,我们就可以使用 Eloquent 动态属性获得相关的记录。动态属性允许你访问关系方法就像访问模型中定义的属性一样:

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

Eloquent 会基于模型名决定外键名称。在这种情况下,会自动假设 Phone 模型有一个 user_id 外键。如果你想覆盖这个约定,可以传递第二个参数给 hasOne 方法:

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

另外,Eloquent 假设外键的值是与父级 id (或自定义 $primaryKey) 列的值相匹配的。换句话说,Eloquent 将会在 Phone 记录的 user_id 列中查找与用户表的 id 列相匹配的值。如果您希望该关联使用 id 以外的自定义键名,则可以给 hasOne 方法传递第三个参数:

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

定义反向关联

我们已经能从 User 模型访问到 Phone 模型了。现在,让我们再在 Phone 模型上定义一个关联,这个关联能让我们访问到拥有该电话的 User 模型。我们可以使用与 hasOne 方法对应的 belongsTo 方法来定义反向关联:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Phone extends Model{  
      /**
     * 获得拥有此电话的用户
     */  
      public function user()  
        {      
          return $this->belongsTo('App\User'); 
         }
      }

在上面的例子中, Eloquent 会尝试匹配 Phone 模型上的 user_idUser 模型上的 id 。它是通过检查关系方法的名称并使用 _id 作为后缀名来确定默认外键名称的。但是,如果 Phone 模型的外键不是 user_id ,那么可以将自定义键名作为第二个参数传递给 belongsTo 方法:

/**
 * 获得拥有此电话的用户
 */
 public function user(){ 
    return $this->belongsTo('App\User', 'foreign_key');
   }

如果父级模型没有使用 id 作为主键,或者是希望用不同的字段来连接子级模型,则可以通过给 belongsTo

/**
 * 获得拥有此电话的用户
 */
 public function user(){ 
    return $this->belongsTo('App\User', 'foreign_key', 'other_key');
  }

하지만 연결 사용에 대해 자세히 알아보기 전에 각 연결 유형을 정의하는 방법을 알아보겠습니다.

일대일

일대일 가장 기본적인 연결관계이다. 예를 들어 User 모델은 Phone 모델과 연결될 수 있습니다. 이 연결을 정의하려면 User 모델에 phone 메서드를 작성해야 합니다. phone 메서드 내에서 hasOne 메서드를 호출하고 결과를 반환합니다. 🎜
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Post extends Model{  
      /**
     * 获取博客文章的评论
     */  
      public function comments()   
       {     
          return $this->hasMany('App\Comment');  
       }
  }
🎜 hasOne 메서드의 첫 번째 매개변수는 해당 클래스의 클래스 이름입니다. 관련 모델. 모델 연관이 정의되면 Eloquent 동적 속성을 사용하여 관련 레코드를 얻을 수 있습니다. 동적 속성을 사용하면 모델에 정의된 속성과 마찬가지로 관계형 메서드에 액세스할 수 있습니다. 🎜
$comments = App\Post::find(1)->comments;foreach ($comments as $comment) {    //}
🎜Eloquent는 모델 이름을 기반으로 외래 키 이름을 결정합니다. 이 경우 Phone 모델에 user_id 외래 키가 있다고 자동으로 가정됩니다. 이 규칙을 무시하려면 hasOne 메소드에 두 번째 매개변수를 전달할 수 있습니다: 🎜
$comment = App\Post::find(1)->comments()->where('title', 'foo')->first();
🎜 또한 Eloquent는 외래 키의 값이 상위 ID의 값과 동일하다고 가정합니다. (또는 사용자 정의 $primaryKey) 열 일치. 즉, Eloquent는 Users 테이블의 id 열과 일치하는 Phone 레코드의 user_id 열에서 값을 찾습니다. 연결에서 id가 아닌 사용자 정의 키 이름을 사용하도록 하려면 hasOne 메소드에 세 번째 매개변수를 전달할 수 있습니다: 🎜
return $this->hasMany('App\Comment', 'foreign_key');
return $this->hasMany('App\Comment', 'foreign_key', 'local_key');
🎜

역방향 연결 정의

🎜우리는 이미 User 모델에서 Phone 모델에 접근할 수 있습니다. 이제 전화를 소유한 User 모델에 대한 액세스를 제공하는 Phone 모델에 또 다른 연결을 정의해 보겠습니다. hasOne 메소드에 해당하는 belongsTo 메소드를 사용하여 역방향 연관을 정의할 수 있습니다: 🎜
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Comment extends Model{ 
    /**
     * 获取此评论所属文章
     */   
     public function post()   
      {      
        return $this->belongsTo('App\Post');   
       }
   }
🎜위의 예에서 Eloquent는 Phone를 일치시키려고 시도합니다. 모델의 user_idUser 모델의 id로 설정하세요. 관계 메서드의 이름을 검사하고 _id를 이름 접미사로 사용하여 기본 외래 키 이름을 결정합니다. 그러나 Phone 모델의 외래 키가 user_id가 아닌 경우 사용자 정의 키 이름이 belongsTo의 두 번째 매개변수로 전달될 수 있습니다. 방법: 🎜
$comment = App\Comment::find(1);
echo $comment->post->title;
🎜상위 모델이 기본 키로 id를 사용하지 않거나 다른 필드를 사용하여 하위 모델을 연결하려는 경우 세 번째 매개변수를 belongsTo에 전달할 수 있습니다. 메소드 상위 데이터 테이블의 사용자 정의 키를 🎜
/**
 * 获取此评论所属文章
 */
 public function post(){
     return $this->belongsTo('App\Post', 'foreign_key');
   }
🎜🎜🎜🎜🎜🎜 형식으로 지정합니다.

일대다

"일대다" 연관은 단일 모델이 임의 개수의 다른 연관된 모델을 갖도록 정의하는 데 사용됩니다. 예를 들어, 블로그 게시물에는 댓글 수가 무한할 수 있습니다. 다른 모든 Eloquent 관계와 마찬가지로 일대다 관계의 정의는 Eloquent 모델에 메소드를 작성하는 것입니다:

/**
 * 获取此评论所属文章
 */
 public function post(){ 
    return $this->belongsTo('App\Post', 'foreign_key', 'other_key');
  }

Eloquent가 Comment 모델의 외래 키 속성을 자동으로 결정한다는 점을 기억하세요. . 관례적으로 Eloquent는 모델 이름의 "snake case" 형식과 _id 접미사를 외래 키 필드로 사용합니다. 따라서 위의 예에서 Eloquent는 Post 모델에 해당하는 Comment의 외래 키가 post_id라고 가정합니다. Comment 模型的外键属性。按照约定,Eloquent 将会使用所属模型名称的 『snake case』形式,再加上 _id 后缀作为外键字段。因此,在上面这个例子中,Eloquent 将假定 Comment 对应到 Post 模型上的外键就是 post_id

一旦关系被定义好以后,就可以通过访问 Post 模型的 comments 属性来获取评论的集合。记住,由于 Eloquent 提供了『动态属性』 ,所以我们可以像访问模型的属性一样访问关联方法:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;class User extends Model{  
      /**
     * 用户拥有的角色
     */   
      public function roles()   
       {      
         return $this->belongsToMany('App\Role');  
        }
     }

当然,由于所有的关联还可以作为查询语句构造器使用,因此你可以使用链式调用的方式,在 comments 方法上添加额外的约束条件:

$user = App\User::find(1);
foreach ($user->roles as $role) {  
  //
}

正如 hasOne 方法一样,你也可以在使用 hasMany 方法的时候,通过传递额外参数来覆盖默认使用的外键与本地键:

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

一对多(反向)

现在,我们已经能获得一篇文章的所有评论,接着再定义一个通过评论获得所属文章的关联关系。这个关联是 hasMany 关联的反向关联,需要在子级模型中使用 belongsTo 方法定义它:

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

这个关系定义好以后,我们就可以通过访问 Comment 模型的 post 这个『动态属性』来获取关联的 Post 模型了:

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

在上面的例子中,Eloquent 会尝试用 Comment 模型的 post_idPost 模型的 id 进行匹配。默认外键名是 Eloquent 依据关联名,并在关联名后加上 _ 再加上主键字段名作为后缀确定的。当然,如果 Comment 模型的外键不是 post_id,那么可以将自定义键名作为第二个参数传递给 belongsTo 方法:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Role extends Model{    
    /**
     * 拥有此角色的用户。
     */   
      public function users()   
       {      
         return $this->belongsToMany('App\User');  
        }
      }

如果父级模型没有使用 id 作为主键,或者是希望用不同的字段来连接子级模型,则可以通过给 belongsTo

관계가 정의되면 Post 모델의 Comments 속성에 액세스하여 댓글 컬렉션을 얻을 수 있습니다. Eloquent는 "동적 속성"을 제공하므로 모델의 속성에 액세스하는 것처럼 관계 메서드에 액세스할 수 있습니다.

$user = App\User::find(1);
foreach ($user->roles as $role) { 
   echo $role->pivot->created_at;
  }
물론 모든 관계는 쿼리문 생성자로도 사용할 수 있으므로 체인 호출 방식을 사용할 수 있습니다. comments 메서드에 대한 제약 조건:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');

hasOne 메서드와 마찬가지로 hasMany 메서드도 사용할 수 있습니다. 추가 매개변수를 전달하여 외래 키 및 로컬 키:
return $this->belongsToMany('App\Role')->withTimestamps();
🎜🎜
🎜🎜One-to- Many (reverse)🎜🎜이제 기사의 댓글을 모두 가져온 다음, 댓글을 통해 기사를 가져오는 연관을 정의할 수 있습니다. 이 연관은 hasMany 연관의 역 연관입니다. 하위 모델에서 이를 정의하려면 belongsTo 메소드를 사용해야 합니다. 🎜
return $this->belongsToMany('App\Podcast')           
     ->as('subscription')                
     ->withTimestamps();
🎜이 관계가 정의된 후 연관된 Post 모델을 얻기 위해 Comment 모델의 post "동적 속성"을 통해 이에 접근할 수 있습니다: 🎜
$users = User::with('podcasts')->get();
foreach ($users->flatMap->podcasts as $podcast) { 
   echo $podcast->subscription->created_at;
 }
🎜위의 예에서 Eloquent는 다음을 시도합니다. Comment 모델의 post_id를 사용하여 Post 모델의 id와 일치시킵니다. 기본 외래 키 이름은 연결 이름에 따라 Eloquent에 의해 결정되며 그 뒤에는 _ 및 기본 키 필드 이름이 접미사로 붙습니다. 물론 Comment 모델의 외래 키가 post_id가 아닌 경우 사용자 정의 키 이름을 belongsTo의 두 번째 매개변수로 전달할 수 있습니다. 방법: 🎜
return $this->belongsToMany('App\Role')->wherePivot('approved', 1);
return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]);
🎜상위 모델이 기본 키로 id를 사용하지 않거나 다른 필드를 사용하여 하위 모델을 연결하려는 경우 세 번째 매개변수를 belongsTo에 전달할 수 있습니다. 메소드 상위 데이터 테이블의 사용자 정의 키를 🎜
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Role extends Model{   
     /**
     * 拥有此角色的所有用户
     */   
     public function users() 
        {   
             return $this->belongsToMany('App\User')->using('App\UserRole'); 
        }
   }
🎜🎜🎜🎜🎜🎜 형식으로 지정합니다.

다대다

다대다 관계는 hasOnehasMany 관계보다 약간 더 복잡합니다. 예를 들어, 사용자는 많은 역할을 가질 수 있으며 이러한 역할은 다른 사용자와 공유됩니다. 예를 들어, 많은 사용자가 "관리자" 역할을 가질 수 있습니다. 이 연결을 정의하려면 users, rolesrole_user라는 세 개의 데이터베이스 테이블이 필요합니다. role_user 테이블은 연관된 두 모델의 알파벳순으로 이름이 지정되며 user_idrole_id 필드를 포함합니다. hasOnehasMany 关联稍微复杂些。举个例子,一个用户可以拥有很多种角色,同时这些角色也被其他用户共享。例如,许多用户可能都有 「管理员」 这个角色。要定义这种关联,需要三个数据库表: usersrolesrole_userrole_user 表的命名是由关联的两个模型按照字母顺序来的,并且包含了 user_idrole_id 字段。

多对多关联通过调用 belongsToMany 这个内部方法返回的结果来定义,例如,我们在 User 模型中定义 roles 方法:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Relations\Pivot;
    class UserRole extends Pivot{   
     //
  }

一旦关联关系被定义后,你可以通过 roles 动态属性获取用户角色:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Role extends Model{   
     /**
     * 拥有此角色的用户。
     */  
       public function users()  
         {     
            return $this->belongsToMany('App\User')                   
                 ->using('App\UserRole')                        
                 ->withPivot([                         
                    'created_by',                            
                    'updated_by'                      
                    ]);  
            }
       }

当然,像其它所有关联模型一样,你可以使用 roles 方法,利用链式调用对查询语句添加约束条件:

/**
 * 标识 ID 是否自增。
 *
 * @var bool
 */
 public $incrementing = true;

正如前面所提到的,为了确定关联连接表的表名,Eloquent 会按照字母顺序连接两个关联模型的名字。当然,你也可以不使用这种约定,传递第二个参数到 belongsToMany 方法即可:

suppliers
    id - integer
users
    id - integer
    supplier_id - integer

history
    id - integer
    user_id - integer

除了自定义连接表的表名,你还可以通过传递额外的参数到 belongsToMany 方法来定义该表中字段的键名。第三个参数是定义此关联的模型在连接表里的外键名,第四个参数是另一个模型在连接表里的外键名:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Supplier extends Model{   
     /**
     * 用户的历史记录。
     */  
       public function userHistory()  
         {      
           return $this->hasOneThrough('App\History', 'App\User');  
          }
       }

定义反向关联

要定义多对多的反向关联, 你只需要在关联模型中调用 belongsToMany 方法。我们在 Role 模型中定义 users 方法:

class Supplier extends Model{  
  /**
     * 用户的历史记录。
     */   
     public function userHistory()   
      {     
         return $this->hasOneThrough(         
            'App\History',            
            'App\User',            
            'supplier_id', // 用户表外键            
             'user_id', // 历史记录表外键            
             'id', // 供应商本地键            
             'id' // 用户本地键     
              );   
          }
      }

如你所见,除了引入模型为 AppUser 外,其它与在 User 模型中定义的完全一样。由于我们重用了 belongsToMany

다대다 연관은 내부 메소드 belongsToMany에 의해 반환된 결과를 호출하여 정의됩니다. 예를 들어 User<에 roles 메소드를 정의합니다. /code> 모델:
countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string
연결이 정의되면 roles 동적 속성을 통해 사용자 역할을 얻을 수 있습니다. 🎜
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Country extends Model{   
     /**
     * 当前国家所有文章。
     */   
      public function posts()  
        {    
            return $this->hasManyThrough('App\Post', 'App\User'); 
         }
     }
🎜물론 다른 모든 연결 모델과 마찬가지로 를 사용할 수 있습니다. >roles 메소드, 체인 호출을 사용하여 쿼리 문에 제약 조건을 추가합니다: 🎜
class Country extends Model{ 
   public function posts()   
    {     
       return $this->hasManyThrough(        
           'App\Post',            
           'App\User',            
           'country_id', // 用户表外键            
           'user_id', // 文章表外键            
           'id', // 国家表本地键            
           'id' // 用户表本地键      
           );  
      }
  }
🎜 앞서 언급했듯이 관련 연결 테이블의 테이블 이름을 결정하기 위해 Eloquent는 두 관련 모델의 이름을 다음과 같이 연결합니다. 알파벳 순서. 물론 이 규칙을 사용하지 않고 두 번째 매개변수를 belongsToMany 메서드에 전달할 수도 있습니다. 🎜
posts
    id - integer
    name - string

users
    id - integer
    name - string

images
    id - integer
    url - string
    imageable_id - integer
    imageable_type - string
🎜연결 테이블의 테이블 이름을 사용자 정의하는 것 외에도 <에 추가 매개변수를 전달할 수도 있습니다. code>belongsToMany
메소드를 사용하여 테이블에 있는 필드의 키 이름을 정의합니다. 세 번째 매개변수는 연결 테이블에서 이 연관을 정의하는 모델의 외래 키 이름이고, 네 번째 매개변수는 연결 테이블에 있는 다른 모델의 외래 키 이름입니다. 🎜
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Image extends Model{   
     /**
     * 获取拥有此图片的模型。
     */    
     public function imageable()  
       {     
          return $this->morphTo();  
        }
       }
     class Post extends Model{  
    /**
     * 获取文章图片。
     */    
     public function image()  
       {       
        return $this->morphOne('App\Image', 'imageable');   
        }
      }
   class User extends Model{   
    /**
     * 获取用户图片。
     */   
     public function image()   
     {     
       return $this->morphOne('App\Image', 'imageable'); 
     }
    }
🎜

역연관 정의

🎜다대다 역연관을 정의하려면 연관 모델에서 belongsToMany 메소드만 호출하면 됩니다. Role 모델에서 users 메소드를 정의합니다: 🎜
$post = App\Post::find(1);
$image = $post->image;
🎜보시다시피 AppUser 모델 도입을 제외하고 다른 모든 것 와 동일합니다. >User는 모델에 정의된 것과 정확히 동일합니다. belongsToMany 메서드를 재사용하므로 사용자 정의 조인 테이블 테이블 이름과 사용자 정의 조인 테이블에 있는 키의 필드 이름도 여기에 적용됩니다. 🎜🎜🎜

중간 테이블 필드 가져오기

방금 배웠듯이, 다대다 관계는 지원을 제공하기 위해 중간 테이블이 필요합니다. Eloquent는 이 테이블과 상호 작용하는 몇 가지 유용한 방법을 제공합니다. 예를 들어 User 개체가 여러 Role 개체와 연결되어 있다고 가정해 보겠습니다. 이러한 연관된 ​​객체를 얻은 후 모델의 pivot 속성을 ​​사용하여 중간 테이블의 데이터에 액세스할 수 있습니다. User 对象关联了多个 Role 对象。在获得这些关联对象后,可以使用模型的 pivot 属性访问中间表的数据:

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

需要注意的是,我们获取的每个 Role 模型对象,都会被自动赋予 pivot 属性,它代表中间表的一个模型对象,并且可以像其他的 Eloquent 模型一样使用。

默认情况下,pivot 对象只包含两个关联模型的主键,如果你的中间表里还有其他额外字段,你必须在定义关联时明确指出:

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

如果你想让中间表自动维护 created_atupdated_at 时间戳,那么在定义关联时附加上 withTimestamps 方法即可:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Comment extends Model{   
     /**
     * 获取拥有此评论的模型。
     */   
      public function commentable() 
         {      
           return $this->morphTo();   
         }
      }
    class Post extends Model{   
    /**
     * 获取此文章的所有评论。
     */  
      public function comments()  
        {    
            return $this->morphMany('App\Comment', 'commentable');  
          }
       }
     class Video extends Model{  
    /**
     * 获取此视频的所有评论。
     */   
     public function comments()  
       {    
           return $this->morphMany('App\Comment', 'commentable');  
       }
    }

自定义 pivot 属性名称

如前所述,来自中间表的属性可以使用 pivot 属性访问。但是,你可以自由定制此属性的名称,以便更好的反应其在应用中的用途。

例如,如果你的应用中包含可能订阅的用户,则用户与博客之间可能存在多对多的关系。如果是这种情况,你可能希望将中间表访问器命名为 subscription 取代 pivot 。这可以在定义关系时使用 as 方法完成:

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

一旦定义完成,你可以使用自定义名称访问中间表数据:

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

通过中间表过滤关系

在定义关系时,你还可以使用 wherePivotwherePivotIn 方法来过滤 belongsToMany

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

우리가 얻는 각 Role 모델 객체는 주목해야 합니다. 에는 중간 테이블의 모델 객체를 나타내며 다른 Eloquent 모델처럼 사용할 수 있는 pivot 속성이 자동으로 할당됩니다.

기본적으로 pivot 객체에는 두 관련 모델의 기본 키만 포함됩니다. 중간 테이블에 다른 추가 필드가 있는 경우 관계를 정의할 때 이를 명시적으로 표시해야 합니다.

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Post extends Model{   
     /**
     * 获取文章的所有标签。
     */   
      public function tags()  
        {     
           return $this->morphToMany('App\Tag', 'taggable');  
         }
      }

중간 테이블이 자동으로 created_atupdated_at 타임스탬프를 유지하도록 하려면 연결을 정의할 때 withTimestamps 메서드를 추가하세요.
<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Tag extends Model{ 
     /**
     * 获取被打上此标签的所有文章。
     */   
      public function posts() 
         {    
             return $this->morphedByMany('App\Post', 'taggable');  
          }   
     /**
     * 获取被打上此标签的所有视频。
     */   
      public function videos()  
        {       
         return $this->morphedByMany('App\Video', 'taggable');  
         }
     }
🎜피벗 속성 이름을 사용자 정의하세요🎜🎜앞서 언급했듯이 중간 테이블의 속성은 피벗<을 사용하여 액세스할 수 있습니다. /코드> 속성 . 그러나 애플리케이션에서의 용도를 더 잘 반영하기 위해 이 속성의 이름을 자유롭게 사용자 정의할 수 있습니다. 🎜🎜예를 들어 앱에 구독할 수 있는 사용자가 포함된 경우 사용자와 블로그 사이에 다대다 관계가 있을 수 있습니다. 이 경우 pivot 대신 중간 테이블 접근자 subscription의 이름을 지정할 수 있습니다. 이는 관계를 정의할 때 as 메소드를 사용하여 수행할 수 있습니다: 🎜
$post = App\Post::find(1);foreach ($post->tags as $tag) { 
   //
}
🎜정의되면 사용자 정의 이름을 사용하여 중간 테이블 데이터에 액세스할 수 있습니다: 🎜
$tag = App\Tag::find(1);foreach ($tag->videos as $video) {
    //
 }
🎜🎜중간 테이블을 통해 관계 필터링🎜🎜관계를 정의할 때 wherePivotwherePivotIn 메서드를 사용하여 belongsToMany를 필터링할 수도 있습니다. 코드> 다음에 대한 결과 반환: 🎜
use Illuminate\Database\Eloquent\Relations\Relation;
Relation::morphMap([ 
   'posts' => 'App\Post',    
   'videos' => 'App\Video',
 ]);
🎜🎜🎜🎜🎜🎜

중간 테이블 모델 정의

사용자 정의 중간 테이블 모델 정의
연관 관계에서 중간 테이블을 나타내는 사용자 정의 모델을 정의하려면 연관 정의 시 using 메서드를 호출하면 됩니다. . 사용자 정의 다대다 중간 테이블 모델은 IlluminateDatabaseEloquentRelationsPivot 클래스에서 확장되어야 하며 사용자 정의 다대다(다형성) 중간 테이블 모델은 IlluminateDatabaseEloquentRelationsMorphPivot 클래스를 상속해야 합니다. 예를 들어, using 方法。自定义多对多中间表模型都必须扩展自 IlluminateDatabaseEloquentRelationsPivot 类,自定义多对多(多态)中间表模型必须继承 IlluminateDatabaseEloquentRelationsMorphPivot 类。例如,
我们在写 Role 模型的关联时,使用自定义中间表模型 UserRole

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class User extends Model{    
    /**
     * 获取该用户的所有文章。
     */  
     public function posts()  
       {     
          return $this->hasMany('App\Post');   
        }
    }

当定义 UserRole 模型时,我们要扩展 Pivot 类:

$user = App\User::find(1);
$user->posts()->where('active', 1)->get();

你可以组合使用 usingwithPivot 从中间表来检索列。例如,通过将列名传递给 withPivot 方法,就可以从 UserRole 中间表中检索出 created_byupdated_by 两列数据。

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

带有递增 ID 的自定义中继模型

如果你用一个自定义的中继模型定义了多对多的关系,而且这个中继模型拥有一个自增的主键,你应当确保这个自定义中继模型类中定义了一个 incrementing 属性其值为 true

// 获取至少存在一条评论的所有文章...
$posts = App\Post::has('comments')->get();

远程一对一关系

远程一对一关联通过一个中间关联模型实现。
例如,如果每个供应商都有一个用户,并且每个用户与一个用户历史记录相关联,那么供应商可以通过用户访问用户的历史记录,让我们看看定义这种关系所需的数据库表:

// 获取评论超过三条的文章...
$posts = App\Post::has('comments', '>=', 3)->get();

虽然 history 表不包含 supplier_id ,但 hasOneThrough 关系可以提供对用户历史记录的访问,以访问供应商模型。现在我们已经检查了关系的表结构,让我们在 Supplier 模型上定义相应的方法:

// 获取拥有至少一条带有投票评论的文章...
$posts = App\Post::has('comments.votes')->get();

传递给 hasOneThrough 方法的第一个参数是希望访问的模型名称,第二个参数是中间模型的名称。

当执行关联查询时,通常会使用 Eloquent 约定的外键名。如果你想要自定义关联的键,可以通过给 hasOneThroughRole 모델의 연관을 작성할 때 사용자 정의 중간 테이블 모델인 UserRole을 사용합니다.

use Illuminate\Database\Eloquent\Builder;
// 获取至少带有一条评论内容包含 foo% 关键词的文章...
$posts = App\Post::whereHas('comments', function ($query)
 { 
    $query->where('content', 'like', 'foo%');})->get();
    // 获取至少带有十条评论内容包含 foo% 关键词的文章...
    $posts = App\Post::whereHas('comments', function ($query)
     { 
        $query->where('content', 'like', 'foo%');
      }, '>=', 10)->get();

UserRole 모델을 정의할 때, Pivot 클래스:

$posts = App\Post::doesntHave('comments')->get();
usingwithPivot을 조합하여 중간 테이블에서 열을 검색할 수 있습니다. 예를 들어 created_byupdated_by는 열 이름을 withPivot에 전달하여 UserRole 중간 테이블에서 검색할 수 있습니다. method > 두 개의 데이터 열.

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

ID가 증가하는 사용자 정의 릴레이 모델

사용자 정의 릴레이 모델 다중 관계로 여러 쌍을 정의하고 릴레이 모델에 자동 증가 기본 키인 경우 사용자 정의 릴레이 모델 클래스가 true 값으로 incrementing 속성을 ​​정의하는지 확인해야 합니다. one-through">🎜🎜
🎜🎜원격 일대일 관계🎜🎜중개 연결 모델 구현을 통한 원격 일대일 연결. 🎜예를 들어, 각 제공업체에 사용자가 있고 각 사용자가 사용자 기록과 연결되어 있는 경우 제공업체는 사용자를 통해 사용자의 기록에 액세스할 수 있습니다. 이 관계를 정의하는 데 필요한 데이터베이스 테이블을 살펴보겠습니다. 🎜
use Illuminate\Database\Eloquent\Builder;
$posts = App\Post::whereDoesntHave('comments.author', function (Builder $query) 
{   
 $query->where('banned', 1);
})->get();
🎜 history 테이블에 supplier_id가 포함되어 있지 않으면 hasOneThrough 관계를 통해 사용자 기록에 대한 액세스를 제공하여 공급업체 모델에 액세스할 수 있습니다. 이제 관계의 테이블 구조를 검사했으므로 Supplier 모델에서 해당 메서드를 정의해 보겠습니다. 🎜
$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post) {
    echo $post->comments_count;
   }
🎜 hasOneThrough 메서드에 전달된 첫 번째 매개변수는 원하는 매개변수입니다. access 모델 이름, 두 번째 매개변수는 중간 모델의 이름입니다. 🎜🎜관련 쿼리를 실행할 때 일반적으로 Eloquent의 기존 외래 키 이름이 사용됩니다. 연관된 키를 사용자 정의하려면 세 번째 및 네 번째 매개변수를 hasOneThrough 메소드에 전달하면 됩니다. 세 번째 매개변수는 중간 모델의 외래 키 이름을 나타내고, 네 번째 매개변수는 나타냅니다. 최종 모델의 외래 키 이름입니다. 다섯 번째 매개변수는 로컬 키 이름을 나타내고, 여섯 번째 매개변수는 중간 모델의 로컬 키 이름을 나타냅니다. 🎜
$posts = App\Post::withCount(['votes', 'comments' => function ($query)
 { 
    $query->where('content', 'like', 'foo%');
  }])->get();
    echo $posts[0]->votes_count;echo $posts[0]->comments_count;
🎜🎜🎜🎜🎜🎜

원격 일대다 연결

원격 일대다 연결은 중간 연결을 통해 원격 수준 연결을 얻는 편리하고 짧은 방법을 제공합니다. 예를 들어 Country 모델은 중간 User 모델을 통해 여러 Post 모델을 가질 수 있습니다. 이 예에서는 특정 국가의 모든 블로그 게시물을 쉽게 수집할 수 있습니다. 이 연결을 정의하는 데 필요한 데이터 테이블을 살펴보겠습니다. Country 模型可以通过中间的 User 模型获得多个 Post 模型。在这个例子中,你可以轻易地收集给定国家的所有博客文章。让我们来看看定义这种关联所需的数据表:

$posts = App\Post::withCount([
    'comments',    
    'comments as pending_comments_count' => function ($query) { 
           $query->where('approved', false);   
      }])->get();
   echo $posts[0]->comments_count;
    echo $posts[0]->pending_comments_count;

虽然 posts 表中不包含 country_id 字段,但 hasManyThrough 关联能让我们通过 $country->posts 访问到一个国家下所有的用户文章。为了完成这个查询,Eloquent 会先检查中间表 userscountry_id 字段,找到所有匹配的用户 ID 后,使用这些 ID,在 posts 表中完成查找。

现在,我们已经知道了定义这种关联所需的数据表结构,接下来,让我们在 Country 模型中定义它:

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

hasManyThrough 方法的第一个参数是我们最终希望访问的模型名称,而第二个参数是中间模型的名称。

当执行关联查询时,通常会使用 Eloquent 约定的外键名。如果你想要自定义关联的键,可以通过给 hasManyThrough 方法传递第三个和第四个参数实现,第三个参数表示中间模型的外键名,第四个参数表示最终模型的外键名。第五个参数表示本地键名,而第六个参数表示中间模型的本地键名:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Book extends Model{  
      /**
     * 获取书籍作者。
     */ 
      public function author() 
         {    
             return $this->belongsTo('App\Author');   
          }
       }

多态关联

多态关联允许目标模型借助单个关联从属于多个模型。

一对一(多态)

表结构

一对一多态关联与简单的一对一关联类似;不过,目标模型能够在一个关联上从属于多个模型。例如,博客 PostUser 可能共享一个关联到 Image 模型的关系。使用一对一多态关联允许使用一个唯一图片列表同时用于博客文章和用户账户。让我们先看看表结构:

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

要特别留意 images 表的 imageable_idimageable_type 列。 imageable_id 列包含文章或用户的 ID 值,而 imageable_type 列包含的则是父模型的类名。Eloquent 在访问 imageable 时使用 imageable_type

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

posts 테이블에는 country_id 필드가 포함되어 있지 않지만 hasManyThrough 연결을 통해 $country->posts를 통해 한 국가의 모든 사용자 게시물에 액세스할 수 있습니다. 이 쿼리를 완료하기 위해 Eloquent는 먼저 중간 테이블 userscountry_id 필드를 확인한 후 일치하는 모든 사용자 ID를 찾은 후 이 ID를 사용하여 에 게시합니다. 게시물 표에서 검색을 완료하세요.
이제 이 연관을 정의하는 데 필요한 데이터 테이블 구조를 알았으므로 이를 Country 모델에서 정의해 보겠습니다.

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

hasManyThrough 메소드 첫 번째 매개변수는 우리가 궁극적으로 접근하고자 하는 모델이고, 두 번째 매개변수는 중간 모델의 이름입니다.

관련 쿼리를 실행할 때 일반적으로 Eloquent의 기존 외래 키 이름이 사용됩니다. 연관된 키를 사용자 정의하려면 세 번째 및 네 번째 매개변수를 hasManyThrough 메소드에 전달하면 됩니다. 세 번째 매개변수는 중간 모델의 외래 키 이름을 나타내고 네 번째 매개변수는 나타냅니다. 최종 모델의 외래 키 이름입니다. 다섯 번째 매개변수는 로컬 키 이름을 나타내고, 여섯 번째 매개변수는 중간 모델의 로컬 키 이름을 나타냅니다.
$books = App\Book::with(['author', 'publisher'])->get();
🎜
🎜

다형성 연관

🎜다형성 연관을 사용하면 대상 모델이 단일 연관을 통해 여러 모델에 종속될 수 있습니다. 🎜🎜🎜
🎜🎜일대일(다형성)🎜< div name="03a0d2" data-unique="03a0d2">🎜🎜테이블 구조🎜🎜일대일 다형성 연관은 단순한 일대일 연관과 유사하지만 대상 모델은 여러 모델에 속할 수 있습니다. 단일 협회. 예를 들어 블로그 PostUserImage 모델과 관계를 공유할 수 있습니다. 일대일 다형성 연관을 사용하면 블로그 게시물과 사용자 계정 모두에 대해 고유한 이미지 목록을 사용할 수 있습니다. 먼저 테이블 구조를 살펴보겠습니다. 🎜
$books = App\Book::with('author.contacts')->get();
🎜 images 테이블의 imageable_idimageable_type 열에 특히 주의하세요. imageable_id 열에는 게시물 또는 사용자 ID 값이 포함되고, imageable_type 열에는 상위 모델의 클래스 이름이 포함됩니다. Eloquent는 imageable에 액세스할 때 상위 모델의 "유형"을 결정하기 위해 imageable_type 열을 사용합니다. 🎜🎜🎜🎜모델 구조🎜🎜다음으로 연관을 설정하기 위한 모델 정의를 살펴보겠습니다. 🎜
$users = App\Book::with('author:id,name')->get();
🎜🎜

연관 가져오기

테이블과 모델이 정의되면 모델을 통해 이 연관에 액세스할 수 있습니다. 예를 들어, 기사 이미지를 얻으려면 image 동적 속성을 사용할 수 있습니다: image 动态属性:

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

还可以通过访问执行 morphTo 调用的方法名来从多态模型中获知父模型。在这个例子中,就是 Image 模型的 imageable 方法。所以,我们可以像动态属性那样访问这个方法:

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

Image 模型的 imageable 关联将返回 PostUser 实例,其结果取决于图片属性哪个模型。

一对多(多态)

表结构

一对多多态关联与简单的一对多关联类似;不过,目标模型可以在一个关联中从属于多个模型。假设应用中的用户可以同时 「评论」 文章和视频。使用多态关联,可以用单个 comments 表同时满足这些情况。我们还是先来看看用来构建这种关联的表结构:

$books = App\Book::all();
if ($someCondition) {
    $books->load('author', 'publisher');
  }

模型结构

接下来,看看构建这种关联的模型定义:

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

获取关联

一旦定义了数据库表和模型,就可以通过模型访问关联。例如,可以使用 comments 动态属性访问文章的全部评论:

public function format(Book $book){
    $book->loadMissing('author');    
    return [    
        'name' => $book->name,        
        'author' => $book->author->name   
       ];
   }

还可以通过访问执行 morphTo 调用的方法名来从多态模型获取其所属模型。在本例中,就是 Comment 模型的  commentable 方法:

<?php
    use Illuminate\Database\Eloquent\Model;
    class ActivityFeed extends Model{   
     /**
     * Get the parent of the activity feed record.
     */   
   public function parentable() 
      {    
          return $this->morphTo(); 
       }
    }

Comment  模型的 commentable 关联将返回 PostVideo 实例,其结果取决于评论所属的模型。

多对多(多态)

表结构

多对多多态关联比 morphOnemorphMany 关联略微复杂一些。例如,博客 PostVideo 模型能够共享关联到 Tag 模型的多态关系。使用多对多多态关联允许使用一个唯一标签在博客文章和视频间共享。以下是多对多多态关联的表结构:

$activities = ActivityFeed::with('parentable')
    ->get()    
    ->loadMorph('parentable', [ 
           Event::class => ['calendar'],        
           Photo::class => ['tags'],        
           Post::class => ['author'],   
          ]);

模型结构

接下来,在模型上定义关联。PostVideo 模型都有调用 Eloquent 基类上  morphToMany 方法的 tags

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

또한 morphTo를 실행하는 메서드 이름에 액세스하여 다형성 모델에서 상위 모델을 가져올 수도 있습니다. 전화하세요. 이 경우 Image 모델의 imageable 메서드입니다. 따라서 동적 속성처럼 이 메서드에 액세스할 수 있습니다.
$post = App\Post::find(1);
$post->comments()->saveMany([ 
   new App\Comment(['message' => 'A new comment.']),    
   new App\Comment(['message' => 'Another comment.']),
 ]);
Image 모델의 imageable 연결은 Post 또는 User를 반환합니다. 인스턴스의 경우 이미지 속성이 어떤 모델인지에 따라 결과가 달라집니다. 🎜🎜🎜
🎜

일대다(다형성) < /h3>
🎜🎜테이블 구조🎜🎜일대다 다형성 연관은 단순한 일대다 연관과 유사하지만 대상 모델은 다음과 같습니다. 하나의 연관 모델에서 다수에 종속됩니다. 애플리케이션의 사용자가 기사와 비디오에 동시에 "댓글"을 달 수 있다고 가정합니다. 다형성 연관을 사용하면 단일 comments 테이블로 이러한 상황을 모두 충족할 수 있습니다. 먼저 이 연관을 구축하는 데 사용된 테이블 구조를 살펴보겠습니다. 🎜
$post = App\Post::find(1);
$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';$post->push();
🎜🎜모델 구조🎜🎜다음으로 이 연관을 구축하는 모델을 살펴보겠습니다. : 🎜
$post = App\Post::find(1);
$comment = $post->comments()->create([
    'message' => 'A new comment.',
  ]);
🎜🎜연관 가져오기 🎜🎜데이터베이스 테이블과 모델이 정의되면 모델을 통해 연관에 접근할 수 있습니다. 예를 들어, comments 동적 속성을 사용하여 기사의 모든 댓글에 액세스할 수 있습니다: 🎜
$post = App\Post::find(1);$post->comments()->createMany([
    [  
          'message' => 'A new comment.',  
     ],    
     [    
           'message' => 'Another new comment.',  
     ],
  ]);
🎜 또한 다음 작업을 수행하는 메서드의 이름에 액세스하여 다형성 모델에서 해당 댓글이 속한 모델을 가져올 수도 있습니다. morphTo 호출. 이 경우 Comment 모델의 commentable 메서드: 🎜
$account = App\Account::find(10);
$user->account()->associate($account);$user->save();
🎜 Comment 모델의 commentable 연결은 를 반환합니다. >게시물 또는 동영상 인스턴스의 경우 결과는 댓글이 속한 모델에 따라 다릅니다. 🎜🎜🎜
🎜

다대다(다형성) < /h3>
🎜🎜테이블 구조🎜🎜다대다 다형성 연관은 morphOnemorphMany보다 약간 더 복잡합니다. 연관 일부. 예를 들어 블로그 게시물동영상 모델은 태그 모델과 다형성 관계를 공유할 수 있습니다. 다대다 다형성 연관을 사용하면 고유한 태그를 사용하여 블로그 게시물과 비디오를 공유할 수 있습니다. 다음은 다대다 다형성 연관의 테이블 구조입니다: 🎜
$user->account()->dissociate();$user->save();
🎜🎜모델 구조🎜🎜다음으로, 모델에 대한 연관을 정의합니다. PostVideo 모델 모두 Eloquent 기본 클래스에서 morphToMany 메서드를 호출하는 tags 메서드가 있습니다. 🎜
/**
 * 获取帖子的作者。
 */
 public function user(){
     return $this->belongsTo('App\User')->withDefault();
   }
🎜🎜

역방향 연관 관계 정의

다음으로 Tag 모델에서 각 연관 모델에 대한 메소드를 정의해야 합니다. 이 예에서는 posts 메소드와 videos 메소드를 정의합니다: Tag 模型上为每个关联模型定义一个方法。在这个示例中,我们将会定义 posts 方法和 videos 方法:

/**
 * 获取帖子的作者。
 */
 public function user(){
     return $this->belongsTo('App\User')->withDefault([ 
            'name' => 'Guest Author', 
          ]);
       }
 /**
 * 获取帖子的作者。
 */
 public function user(){
     return $this->belongsTo('App\User')->withDefault(function ($user) {
             $user->name = 'Guest Author'; 
            });
        }

获取关联

一旦定义了数据库表和模型,就可以通过模型访问关联。例如,可以使用 tags 动态属性访问文章的所有标签:

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

还可以访问执行 morphedByMany 方法调用的方法名来从多态模型获取其所属模型。在这个示例中,就是 Tag  模型的 postsvideos 方法。可以像动态属性一样访问这些方法:

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

自定义多态类型

默认情况下, Laravel 使用完全限定类名存储关联模型类型。在上面的一对多示例中, 因为 Comment 可能从属于一个 Post 或一个 Video,默认的 commentable_type 就将分别是 AppPostAppVideo。不过,你可能希望数据库与应用的内部结构解耦。在这种情况下,可以定义一个 「morph 映射」 来通知 Eloquent 使用自定义名称代替对应的类名:

// 移除用户的一个角色...
$user->roles()->detach($roleId);
// 移除用户的所有角色...
$user->roles()->detach();

可以在 AppServiceProvider 的  boot 函数中注册 morphMap,或者创建一个单独的服务提供者。

查询关联

由于 Eloquent 关联的所有类型都通过方法定义,你可以调用这些方法,而无需真实执行关联查询。另外,所有 Eloquent 关联类型用作 查询构造器,允许你在数据库上执行 SQL 之前,持续通过链式调用添加约束。

例如,假设一个博客系统的 User 模型有许多关联的 Post 模型:

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

你可以查询 posts

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

Get 연관

데이터베이스 테이블과 모델이 정의되면 모델을 통해 관계에 접근할 수 있습니다. 예를 들어 tags 동적 속성을 사용하여 기사의 모든 태그에 액세스할 수 있습니다.

$user->roles()->sync([1 => ['expires' => true], 2, 3]);
또한 morphedByMany 메소드 호출을 실행하는 메소드 이름에 액세스하여 다형성 모델에 속하는 모델입니다. 이 예에서는 Tag 모델의 posts 또는 videos 메서드입니다. 이러한 메소드는 동적 속성처럼 액세스할 수 있습니다:

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

사용자 정의 다형성 유형 🎜기본적으로 Laravel은 정규화된 클래스 이름을 사용하여 관련 모델 유형을 저장합니다. 위의 일대다 예에서 댓글게시물 또는 동영상에 속할 수 있으므로 기본 commentable_type는 각각 AppPost 또는 AppVideo입니다. 그러나 애플리케이션의 내부 구조에서 데이터베이스를 분리할 수도 있습니다. 이 경우 "모프 매핑"을 정의하여 해당 클래스 이름 대신 사용자 정의 이름을 사용하도록 Eloquent에 알릴 수 있습니다. 🎜
$user->roles()->toggle([1, 2, 3]);
🎜 AppServiceProvider<의 boot 함수에서 수행할 수 있습니다. /code> morphMap을 등록하거나 별도의 서비스 공급자를 만듭니다. 🎜🎜
🎜🎜
🎜

관계 쿼리

🎜모든 유형의 Eloquent 관계는 메소드를 통해 정의되므로 , 관련 쿼리를 실제로 실행하지 않고도 이러한 메서드를 호출할 수 있습니다. 또한 모든 Eloquent 관계 유형은 쿼리 빌더 역할을 하여 데이터베이스에서 SQL을 실행하기 전에 호출 체인을 통해 지속적으로 제약 조건을 추가할 수 있습니다. 🎜🎜예를 들어, 블로그 시스템의 User 모델에 연결된 Post 모델이 많이 있다고 가정해 보세요. 🎜
App\User::find(1)->roles()->save($role, ['expires' => $expires]);
🎜posts 연결을 쿼리하고 이를 제공할 수 있습니다. 추가 제약 조건 추가: 🎜
$user = App\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);
🎜 연결에서 쿼리 빌더 방법을 사용할 수 있습니다. 어떤 방법이 유용할지 알아보려면 쿼리 빌더 설명서를 참조하세요. 🎜🎜🎜🎜🎜🎜🎜

Relation Methods Vs. Dynamic Properties

Eloquent 관계 쿼리에 추가 제약 조건을 추가할 필요가 없다면 속성처럼 관계에 액세스할 수 있습니다. 예를 들어 UserPost 예제 모델을 계속 사용하면 다음과 같이 사용자의 모든 게시물에 액세스할 수 있습니다. UserPost 示例模型,可以这样访问用户的全部文章:

<?php
    namespace App;
    use Illuminate\Database\Eloquent\Model;
    class Comment extends Model{ 
       /**
     * 要触发的所有关联关系
     *
     * @var array
     */  
      protected $touches = ['post'];   
     /**
     * 评论所属的文章
     */   
     public function post() 
        {     
           return $this->belongsTo('App\Post');  
         }
      }

动态属性是「懒加载」的,这意味着它们仅在你真实访问关联数据时才被载入。因此,开发者经常使用 预加载 预先加载那些他们确知在载入模型后将访问的关联。对载入模型关联中必定被执行的 SQL 查询而言,预加载显著减少了查询的执行次数。

查询已存在的关联

在访问模型记录时,可能希望基于关联的存在限制查询结果。比如想要获取至少存在一条评论的所有文章,可以通过给 hasorHas 方法传递关联名称来实现:

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

还可以指定运算符和数量进一步自定义查询:

rrreee

还可以用 「点」语法构造嵌套的 has 语句。比如,可以获取拥有至少一条评论和投票的文章:

rrreee

如果需要更多功能,可以使用 whereHasorWhereHas 方法将「where」 条件放到 has 查询上。这些方法允许你向关联加入自定义约束,比如检查评论内容:

rrreee

查询不存在的关联

在访问模型记录时,可能希望基于关联不存在来限制查询结果。假设想要获取存在任何评论的文章,可以通过向 doesntHaveorDoesntHave 方法传递关联名称来实现:

rrreee

如果需要更多功能,可以使用 whereDoesntHaveorWhereDoesntHave 方法将「where」 条件加到 doesntHaverrreee

동적 속성은 "지연 로드"됩니다. 연결된 데이터가 실제로 액세스할 때만 로드된다는 의미입니다. 따라서 개발자는 종종 eager-loading

을 사용하여 모델을 로드한 후 액세스하게 될 관계를 미리 로드합니다. 모델 연결을 로드할 때 실행해야 하는 SQL 쿼리의 경우 즉시 로드를 사용하면 쿼리 실행 횟수가 크게 줄어듭니다.

기존 관계 쿼리
🎜모델 레코드에 액세스할 때 다음을 기반으로 할 수 있습니다. 관계의 존재는 쿼리 결과를 제한합니다. 예를 들어, 댓글이 하나 이상 포함된 모든 기사를 가져오려면 연결 이름을 hasorHas 메소드에 전달할 수 있습니다. 🎜rrreee🎜 또한 지정할 수도 있습니다 추가 사용자 정의 쿼리를 위한 연산자 및 수량: 🎜rrreee🎜 "점" 구문을 사용하여 중첩된 has 문을 구성할 수도 있습니다. 예를 들어, 댓글과 투표가 하나 이상 포함된 기사를 얻을 수 있습니다. 🎜rrreee🎜더 많은 기능이 필요한 경우 whereHasorWhereHas 메소드를 사용하여 " < code>has
쿼리의 where" 조건입니다. 이러한 방법을 사용하면 댓글 내용 확인과 같은 관계에 사용자 지정 제약 조건을 추가할 수 있습니다. 🎜rrreee🎜🎜🎜
🎜🎜 존재하지 않는 관계에 대한 쿼리🎜🎜모델 레코드에 액세스할 때 관계가 존재하지 않음을 기준으로 쿼리 결과를 제한할 수 있습니다. 댓글이 없는 기사를 가져오려고 한다고 가정해 보겠습니다. doesntHaveorDoesntHave 메소드에 연결 이름을 전달하면 됩니다. 🎜 rrreee🎜필요한 경우 더 많은 기능을 사용하려면 whereDoesntHaveorWhereDoesntHave 메서드를 사용하여 doesntHave 쿼리에 "where" 조건을 추가할 수 있습니다. 이러한 방법을 사용하면 댓글 내용 감지와 같은 연결에 사용자 정의 제한을 추가할 수 있습니다. 🎜rrreee🎜 "점" 구문을 사용하여 중첩된 연결 쿼리를 수행할 수도 있습니다. 예를 들어, 금지되지 않은 작성자의 댓글이 포함된 기사를 가져오는 데 다음 쿼리가 사용됩니다. 🎜rrreee🎜🎜🎜🎜🎜🎜

관계 모델 개수

연관 결과를 실제로 로드하지 않고 통계적인 개수만 계산하려는 경우 {relation}_count에 배치되는 withCount 메서드를 사용할 수 있습니다. < 결과 모델 /code> 열. 예는 다음과 같습니다. withCount 方法,它将放在结果模型的 {relation}_count 列。示例如下:

rrreee

可以像给查询添加限制一样为多个关系添加「计数」:

rrreee

还可以给关联计数结果起别名,这允许你在同一关联上添加多个计数:

rrreee

如果将 withCountselect 查询组装在一起,请确保在 select 方法之后调用 withCount

rrreee

预加载

当以属性方式访问 Eloquent 关联时,关联数据「懒加载」。这着直到第一次访问属性时关联数据才会被真实加载。不过 Eloquent 能在查询父模型时「预先载入」子关联。预加载可以缓解 N + 1 查询问题。为了说明 N + 1 查询问题,考虑  Book 模型关联到 Author 的情形:

rrreee

现在,我们来获取所有的书籍及其作者:

rrreee

此循环将执行一个查询,用于获取全部书籍,然后为每本书执行获取作者的查询。如果我们有 25 本书,此循环将运行 26 个查询:1 个用于查询书籍,25 个附加查询用于查询每本书的作者。

谢天谢地,我们能够使用预加载将操作压缩到只有 2 个查询。在查询时,可以使用 with 方法指定想要预加载的关联:

rrreee

在这个例子中,仅执行了两个查询:

rrreee

预加载多个关联

有时,你可能需要在单一操作中预加载几个不同的关联。要达成此目的,只要向 with 方法传递多个关联名称构成的数组参数:

rrreee

嵌套预加载

可以使用 「点」 语法预加载嵌套关联。比如在一个 Eloquent 语句中预加载所有书籍作者及其联系方式:

rrreee

预加载指定列

并不是总需要获取关系的每一列。在这种情况下,Eloquent 允许你为关联指定想要获取的列:

rrreee

{note} 在使用这个特性时,一定要在要获取的列的列表中包含 idrrreee

쿼리에 제한을 추가하는 것처럼 여러 관계에 "개수"를 추가할 수 있습니다.
rrreee

또한 관계 개수 결과에 별칭을 지정하여 동일한 관계에 여러 개수를 추가할 수도 있습니다. rrreeewithCountselect 쿼리를 함께 조합하려면 select 메서드 다음에 withCount를 호출해야 합니다.

rrreee
< a name="eager-loading">
🎜
🎜

Eager-loading

🎜Eloquent 연결을 속성으로 액세스하는 경우 , 관련 데이터는 "지연" 로드입니다. 이렇게 하면 속성에 처음 액세스할 때까지 관련 데이터가 실제로 로드되지 않습니다. 그러나 Eloquent는 상위 모델을 쿼리할 때 하위 관계를 "미리 로드"할 수 있습니다. 즉시 로딩은 N+1 쿼리 문제를 완화할 수 있습니다. N + 1 쿼리 문제를 설명하기 위해 Book 모델이 Author와 연결된 경우를 생각해 보세요. 🎜rrreee🎜이제 모든 책과 해당 저자를 가져오겠습니다. 🎜 rrreee🎜This 루프는 모든 책을 가져오는 쿼리를 실행한 다음 각 책에 대해 저자를 가져오는 쿼리를 실행합니다. 25권의 책이 있는 경우 이 루프는 26개의 쿼리를 실행합니다. 1개는 책을 쿼리하고 25개의 추가 쿼리는 각 책의 저자를 쿼리합니다. 🎜🎜다행히 Eager 로딩을 사용하여 작업을 단 2개의 쿼리로 압축할 수 있었습니다. 쿼리 시 with 메서드를 사용하여 미리 로드할 연결을 지정할 수 있습니다. 🎜rrreee🎜이 예에서는 두 개의 쿼리만 실행되었습니다: 🎜rrreee
🎜

여러 연결 미리 로드

🎜때때로 단일 작업에서 여러 다른 연결을 미리 로드해야 할 수도 있습니다. 이를 달성하려면 여러 개의 연관된 이름으로 구성된 배열 매개변수를 with 메소드에 전달하면 됩니다: 🎜rrreee
🎜

중첩된 사전 설정

🎜"점" 구문을 사용하여 중첩된 연결을 미리 로드할 수 있습니다. 예를 들어, 하나의 Eloquent 문에 모든 책 저자와 연락처 정보를 미리 로드합니다: 🎜rrreee
🎜

지정된 열을 미리 로드

🎜하는 것이 항상 필요한 것은 아닙니다. 관계의 각 열. 이 경우, Eloquent를 사용하면 연결에 대해 얻고 싶은 열을 지정할 수 있습니다: 🎜rrreee
🎜{note} 이 기능을 사용할 때 가져올 열 목록에 id 열. 🎜🎜🎜🎜🎜🎜🎜🎜

미리 로드에 대한 제약 조건 추가

때때로 다음 예와 같이 추가 쿼리 조건을 사전 로드 쿼리에 추가하는 동안 관계를 사전 로드할 수도 있습니다:

rrreee

이 예에서 Eloquent는 제목이 < /code> 열에는 first 키워드가 포함되어 있습니다. 다른 쿼리 빌더 메서드를 호출하여 사전 로드 작업을 추가로 사용자 정의할 수도 있습니다. title 列包含 first 关键词的文章。也可以调用其它的 查询构造器 方法进一步自定义预加载操作:

rrreee

{note} 在约束预加载时,不能使用 limittake 查询构造器方法。

预加载

有可能你还希望在模型加载完成后在进行渴求式加载。举例来说,如果你想要动态的加载关联数据,那么 load 方法对你来说会非常有用:

rrreee

如果你想要在渴求式加载的查询语句中进行条件约束,你可以通过数组的形式去加载,键为对应的关联关系,值为 Closure 闭包函数,该闭包的参数为一个 query 实例:

rrreee

当关联关系没有被加载时,你可以使用 loadMissing 方法:

rrreee

嵌套延迟加载 & morphTo

如果希望快速加载 morphTo 关系,以及该关系可能返回的各种实体上的嵌套关系,可以使用 loadMorph 方法。

这个方法接受 morphTo 关系的名称作为它的第一个参数,第二个参数接收模型数组、关系数组。为了帮助说明这个方法,可以看一下以下模型例子:

rrreee

在这个例子中,让我们假设 EventPhotoPost 模型可以创建 ActivityFeed 模型。此外,让我们假设 Event 模型属于 Calendar 模型,Photo 模型与 Tag 模型相关联,Post 模型属于 Author 模型。

使用这些模型定义和关系,我们可以检索 ActivityFeed 模型实例,并立即加载所有 parentablerrreee

{note} 사전 로드를 제한하는 경우 limittake 쿼리 빌더를 사용할 수 없습니다. 방법.

Preloading

모델 로딩을 완료하고 싶을 수도 있습니다. 그런 다음 목마른 로딩을 수행합니다. 예를 들어 관련 데이터를 동적으로 로드하려는 경우 load 메서드가 매우 유용할 것입니다.

rrreee Eager Loading 쿼리 문에서 조건부로 제한하려는 경우 로드할 수 있습니다. 배열 형식이며 키는 해당 연결이고 값은 Closure 클로저 함수이고 클로저의 매개변수는 query 인스턴스입니다. rrreee

연관이 로드되지 않은 경우 loadMissing 메소드를 사용할 수 있습니다:
rrreee

중첩 지연 로딩& morphTo< /code>

🎜morphTo 관계뿐만 아니라 관계가 반환할 수 있는 다양한 엔터티의 중첩 관계를 빠르게 로드하려면 loadMorph 방법. 🎜🎜이 메소드는 morphTo 관계의 이름을 첫 번째 매개변수로 받아들이고, 두 번째 매개변수는 모델 배열과 관계 배열을 받습니다. 이 접근 방식을 설명하는 데 도움이 되도록 다음 모델 예를 살펴보십시오. 🎜rrreee🎜이 예에서는 Event , PhotoPost를 가정하겠습니다. 모델은 ActivityFeed 모델을 생성할 수 있습니다. 또한 Event 모델이 Calendar 모델에 속하고 Photo 모델이 Tag 모델이고 Post 모델은 Author 모델에 속합니다. 🎜🎜이러한 모델 정의 및 관계를 사용하여 ActivityFeed 모델 인스턴스를 검색하고 모든 부모 가능 모델과 각각의 중첩 관계를 한 번에 로드할 수 있습니다. 🎜rrreee🎜🎜🎜🎜 🎜 🎜🎜관련 모델 삽입 및 업데이트🎜🎜🎜🎜🎜🎜🎜

저장 방법

Eloquent는 새 모델에 연관을 추가하는 편리한 방법을 제공합니다. 예를 들어 게시물 모델에 새 댓글을 추가해야 할 수도 있습니다. Comment에서 post_id 속성을 ​​수동으로 설정할 필요가 없으며, 관련 모델의 save 메소드를 직접 사용하여 를 저장할 수 있습니다. >Comment 직접 삽입: Comment 到一个 Post 模型中。你不用在 Comment 中手动设置 post_id 属性,就可以直接使用关联模型的 save 方法将 Comment 直接插入:

rrreee

需要注意的是,我们并没有使用动态属性的方式访问 comments 关联。相反,我们调用 comments 方法来获得关联实例。save 方法将自动添加适当的 post_id 值到 Comment 模型中。

如果你需要保存多个关联模型,你可以使用 saveMany 方法:

rrreee

递归保存模型和关联数据

如果你想 save 你的模型及其所有关联数据,你可以使用 push 方法:

rrreee

新增方法

除了 savesaveMany 方法外,你还可以使用 create 方法。它接受一个属性数组,同时会创建模型并插入到数据库中。 还有, save 方法和 create 方法的不同之处在于, save 方法接受一个完整的 Eloquent 模型实例,而 create 则接受普通的 PHP 数组:

rrreee

{tip} 在使用 create 方法前,请务必确保查看过本文档的 批量赋值 章节。

你还可以使用 createMany 方法去创建多个关联模型:

rrreee

你还可以使用 findOrNewfirstOrNewfirstOrCreateupdateOrCreate 方法来 创建和更新关系模型.

更新 belongsTo 关联

当更新 belongsTo 关联时,可以使用 associate 方法。此方法将会在子模型中设置外键:

rrreee

当移除 belongsTo 关联时,可以使用 dissociate 方法。此方法会将关联外键设置为 nullrrreee

comments 연결에 액세스하기 위해 동적 속성을 사용하지 않는다는 점에 유의해야 합니다. 대신 comments 메서드를 호출하여 관련 인스턴스를 가져옵니다. save 메소드는 적절한 post_id 값을 Comment 모델에 자동으로 추가합니다.

여러 관련 모델을 저장해야 하는 경우 saveMany 메서드를 사용할 수 있습니다. rrreee

🎜

모델 및 관련 데이터를 반복적으로 저장

🎜모델 및 모든 관련 데이터를 저장하려면 push<를 사용할 수 있습니다. / code> 방법:🎜rrreee🎜
🎜🎜
🎜🎜새 방법🎜🎜저장 제외saveMany 메소드 외에도 create 메소드를 사용할 수도 있습니다. 이는 속성 배열을 받아들이고 모델을 생성하여 데이터베이스에 삽입합니다. 또한 save 메소드와 create 메소드의 차이점은 save 메소드는 완전한 Eloquent 모델 인스턴스를 허용하는 반면 create 는 일반 PHP 배열을 허용합니다: 🎜rrreee
🎜{tip} create 메서드를 사용하기 전에 이 문서의 일괄 할당 장을 확인하세요. 🎜
🎜 createMany 메서드를 사용하여 여러 관련 모델을 만들 수도 있습니다. 🎜rrreee🎜 findOrNew, firstOrNew를 사용할 수도 있습니다. , firstOrCreateupdateOrCreate 메소드를 사용하여 관계 모델을 생성하고 업데이트합니다.🎜🎜
🎜🎜
🎜🎜belongsTo 연결 업데이트 🎜🎜belongsTo 연결을 업데이트할 때 associate 메서드를 사용할 수 있습니다 . 이 메소드는 하위 모델에 외래 키를 설정합니다: 🎜rrreee🎜 belongsTo 연관을 제거할 때 dissociate 메소드를 사용할 수 있습니다. 이 메소드는 연관된 외래 키를 null로 설정합니다:🎜rrreee🎜🎜🎜🎜🎜🎜

기본 모델

belongsTo 관계를 사용하면 기본 모델을 지정할 수 있습니다. 주어진 관계가 null이면 기본 모델이 반환됩니다. 이 패턴을 Null 객체 패턴이라고 하며 코드에서 불필요한 검사를 줄일 수 있습니다. 아래 예에서 게시된 게시물의 작성자를 찾을 수 없는 경우 user 관계는 빈 AppUser 모델을 반환합니다. belongsTo 关系允许你指定默认模型,当给定关系为 null 时,将会返回默认模型。 这种模式被称作 Null 对象模式 ,可以减少你代码中不必要的检查。在下面的例子中,如果发布的帖子没有找到作者, user 关系会返回一个空的 AppUser 模型:

rrreee

如果需要在默认模型里添加属性, 你可以传递数组或者回调方法到 withDefault 中:

rrreee

多对多关联

附加 / 分离

Eloquent 也提供了一些额外的辅助方法,使相关模型的使用更加方便。例如,我们假设一个用户可以拥有多个角色,并且每个角色都可以被多个用户共享。给某个用户附加一个角色是通过向中间表插入一条记录实现的,可以使用 attach 方法完成该操作:

rrreee

在将关系附加到模型时,还可以传递一组要插入到中间表中的附加数据:

rrreee

当然,有时也需要移除用户的角色。可以使用 detach 移除多对多关联记录。detach 方法将会移除中间表对应的记录;但是这 2 个模型都将会保留在数据库中:

rrreee

为了方便,attachdetach 也允许传递一个 ID 数组:

rrreee

同步关联

你也可以使用 sync 方法构建多对多关联。sync 方法接收一个 ID 数组以替换中间表的记录。中间表记录中,所有未在 ID 数组中的记录都将会被移除。所以该操作结束后,只有给出数组的 ID 会被保留在中间表中:

rrreee

你也可以通过 ID 传递额外的附加数据到中间表:

rrreee

如果你不想移除现有的 ID,可以使用 syncWithoutDetaching 方法:

rrreee

切换关联

多对多关联也提供了 togglerrreee

에 속성을 추가해야 하는 경우 기본 모델인 경우 배열 또는 콜백 메서드를 withDefault에 전달할 수 있습니다:
rrreee

다대다 연결

Attach/Detach
Eloquent는 또한 다음을 제공합니다. 몇 가지 추가 보조 방법을 사용하면 관련 모델을 더욱 편리하게 사용할 수 있습니다. 예를 들어, 사용자가 여러 역할을 가질 수 있고 각 역할을 여러 사용자가 공유할 수 있다고 가정해 보겠습니다. 사용자에게 역할을 추가하려면 중간 테이블에 레코드를 삽입해야 합니다. 이 작업은 attach 메서드를 사용하여 완료할 수 있습니다. 🎜rrreee🎜모델에 관계를 연결할 때 요구 사항 집합 중간 테이블에 삽입된 추가 데이터: 🎜rrreee🎜 물론 때로는 사용자 역할을 제거해야 하는 경우도 있습니다. 다대다 관련 레코드는 분리를 사용하여 제거할 수 있습니다. detach 메소드는 중간 테이블에 해당하는 레코드를 제거하지만 다음 두 모델은 데이터베이스에 유지됩니다. 🎜rrreee🎜 편의상 attach detach< /code>를 사용하면 ID 배열을 전달할 수도 있습니다. 🎜rrreee
🎜🎜동기화 연결🎜🎜sync 메서드를 사용하여 빌드할 수도 있습니다. 다중 다대다 연관. sync 메소드는 ID 배열을 수신하여 중간 테이블의 레코드를 대체합니다. 중간 테이블 레코드 중 ID 배열에 없는 레코드는 모두 제거됩니다. 따라서 작업 후에는 지정된 배열의 ID만 중간 테이블에 유지됩니다. 🎜rrreee🎜 또한 ID별로 추가 추가 데이터를 중간 테이블에 전달할 수도 있습니다. 🎜rrreee🎜 기존 항목을 제거하지 않으려는 경우 ID, syncWithoutDetaching 메소드를 사용할 수 있습니다: 🎜rrreee
🎜🎜Toggle 연관 🎜🎜다대다 연관도 제공 토글 지정된 ID 배열의 연결된 상태를 "토글"하는 데 사용되는 메서드입니다. 주어진 ID가 중간 테이블에 추가된 경우 제거됩니다. 마찬가지로 지정된 ID가 제거되면 추가됩니다. 🎜rrreee🎜🎜🎜중간 테이블에 저장 추가 데이터🎜🎜를 처리할 때 다대다 관계에서 save 메소드는 두 번째 매개변수로 추가 데이터 배열을 받습니다: 🎜rrreee🎜🎜

중간 테이블 레코드 업데이트

중간 테이블의 기존 레코드를 업데이트해야 하는 경우 updateExistingPivot를 사용할 수 있습니다. 이 메소드는 중간 테이블의 외래 키와 업데이트를 위해 업데이트할 데이터 배열을 수신합니다: updateExistingPivot 。此方法接收中间表的外键与要更新的数据数组进行更新:

rrreee

更新父级时间戳

当一个模型属 belongsTo 或者 belongsToMany 另一个模型时, 例如 Comment 属于 Post,有时更新子模型导致更新父模型时间戳非常有用。例如,当 Comment 模型被更新时,您要自动「触发」父级 Post 模型的 updated_at 时间戳的更新。Eloquent 让它变得简单。只要在子模型加一个包含关联名称的 touches 属性即可:

rrreee

现在,当你更新一个 Comment 时,对应父级 Post 模型的 updated_at 字段同时也会被更新,使其更方便得知何时让一个 Postrrreee

상위 타임스탬프 업데이트

모델이 belongsTo에 속하거나 belongsToMany가 다른 모델에 속하는 경우(예: Comment은 < code>Post에 속하므로 업데이트된 상위 모델 타임스탬프를 생성하는 하위 모델을 업데이트하는 것이 유용한 경우가 있습니다. 예를 들어, Comment 모델이 업데이트되면 상위 Post 모델의 updated_at 타임스탬프 업데이트를 자동으로 "트리거"하려고 합니다. Eloquent를 사용하면 쉬워집니다. 연관된 이름이 포함된 하위 모델에 touches 속성을 ​​추가하기만 하면 됩니다.
rrreee🎜이제 Comment를 업데이트하면 해당 상위 Post 모델의 updated_at 필드도 업데이트되어 Post 모델의 캐시를 언제 무효화해야 하는지 더 쉽게 알 수 있습니다. 🎜rrreee🎜이 기사는 🎜에 처음 게재되었습니다. LearnKu.com🎜 웹사이트. 🎜🎜