修改理由:

新增一对一多态关联,并更新多态关联

相关信息:


此投稿已在 5年前 合并。

内容修改:

红色背景 为原始内容

绿色背景 为新增或者修改的内容

OldNewDifferences
77   - [一对多 (反向)](#one-to-many-inverse)
88   - [多对多](#many-to-many)
99   - [远程一对多](#has-many-through)
10    - [多态关联](#polymorphic-relations)
11    - [多对多多态关联](#many-to-many-polymorphic-relations)
 10- [多态关联](#polymorphic-relations)
 11   - [一对一](#one-to-one-polymorphic-relations)
 12   - [一对多](#one-to-many-polymorphic-relations)
 13   - [多对多](#many-to-many-polymorphic-relations)
 14   - [自定义多态类型](#custom-polymorphic-types)
1215- [查询关联](#querying-relations)
1316   - [关联方法 Vs. 动态属性](#relationship-methods-vs-dynamic-properties)
1417   - [基于存在的关联查询](#querying-relationship-existence)
 
3336- [一对多](#one-to-many)
3437- [多对多](#many-to-many)
3538- [远程一对多](#has-many-through)
36 - [多态关联](#polymorphic-relations)
37 - [多对多多态关联](#many-to-many-polymorphic-relations)
 39- [一对一 (多态关联)](#one-to-one-polymorphic-relations)
 40- [一对多 (多态关联)](#one-to-many-polymorphic-relations)
 41- [多对多 (多态关联)](#many-to-many-polymorphic-relations)
3842
3943<a name="defining-relationships"></a>
4044## 定义关联
 
423427   }
424428
425429<a name="polymorphic-relations"></a>
426 ### 多态关联
 430## 多态关联
 431
 432多态关联允许一个模型在单个关联上属于多个其他模型。
 433
 434<a name="one-to-one-polymorphic-relations"></a>
 435### 一对一 (多态关联)
427436
428437#### 数据表结构
429438
430 多态关联允许一个模型在单个关联上属于多个其他模型。例如,想象一下使用你应用的用户可以「评论」文章和视频。使用多态关联,你可以用一个 `comments` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构:
 439一对一的多态关联类似于简单的一对一关联,但目标模型可以在单个关联上属于多个其他模型。例如,博客文章和用户可以共享与图像模型的多态关联,使用一对一的多态关联,您可以用一个 `images` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构:
 440
 441   posts
 442       id - integer
 443       title - string
 444       body - text
 445
 446   users
 447       id - integer
 448       title - string
 449       url - string
 450
 451   images
 452       id - integer
 453       body - text
 454       imageable_id - integer
 455       imageable_type - string
 456
 457`images` 表中有两个需要注意的重要字段 `imageable_id` 和 `imageable_type`。`imageable_id` 用来保存文章或者用户的 ID 值,而 `imageable_type` 用来保存所属模型的类名。Eloquent 使用 `imageable_type` 来决定我们访问关联模型时,要返回的父模型的「类型」。
 458
 459#### 模型结构
 460
 461接下来,我们来看看创建这种关联所需的模型定义:
 462
 463   <?php
 464
 465   namespace App;
 466
 467   use Illuminate\Database\Eloquent\Model;
 468
 469   class Image extends Model
 470   {
 471       /**
 472        * 获得拥有此图像的模型。
 473        */
 474       public function imageable()
 475       {
 476           return $this->morphTo();
 477       }
 478   }
 479
 480   class Post extends Model
 481   {
 482       /**
 483        * 获得此文章的图像。
 484        */
 485       public function image()
 486       {
 487           return $this->morphOne('App\Image', 'imageable');
 488       }
 489   }
 490
 491   class User extends Model
 492   {
 493       /**
 494        * 获得此用户的图像。
 495        */
 496       public function image()
 497       {
 498           return $this->morphOne('App\Image', 'imageable');
 499       }
 500   }
 501
 502#### 获取多态关联
 503
 504一旦你的数据库表准备好、模型定义完成后,就可以通过模型来访问关联了。例如,我们只要简单地使用 `image` 动态属性,就可以获得某篇文章的图像:
 505
 506   $post = App\Post::find(1);
 507
 508   $image = $post->image;
 509
 510你也可以在多态模型上,通过访问调用了 `morphTo` 的关联方法获得多态关联的拥有者。在当前例子中,是 `Image` 模型的 `imageable` 方法。所以,我们可以使用动态属性来访问这个方法:
 511
 512   $image = App\Image::find(1);
 513
 514   $imageable = $image->imageable;
 515
 516`Image` 模型的 `imageable` 关联会返回 `Post` 或者 `User` 实例,这取决于图像所属的模型类型。
 517
 518<a name="one-to-many-polymorphic-relations"></a>
 519### 一对多 (多态关联)
 520
 521#### 数据表结构
 522
 523一对多的多态关联类似于简单的一对多关联,但目标模型可以在单个关联上属于多个其他模型。例如,您的应用程序的用户可以「评论」文章和视频,使用一对多的多态关联,您可以用一个 `comments` 表同时满足这两个使用场景。让我们来看看构建这种关联所需的数据表结构:
431524
432525   posts
433526       id - integer
 
445538       commentable_id - integer
446539       commentable_type - string
447540
448 `comments` 表中有两个需要注意的重要字段 `commentable_id` 和 `commentable_type`。`commentable_id` 用来保存文章或者视频的 ID 值,而 `commentable_type` 用来保存所属模型的类名。`commentable_type` 是在我们访问 `commentable` 关联时, 让 ORM 确定所属的模型是哪个「类型」。
 541`comments` 表中有两个需要注意的重要字段 `commentable_id` 和 `commentable_type`。`commentable_id` 用来保存文章或者视频的 ID 值,而 `commentable_type` 用来保存所属模型的类名。Eloquent 使用 `commentable_type` 来决定我们访问关联模型时,要返回的父模型的「类型」。
449542
450543#### 模型结构
451544
 
508601
509602`Comment` 模型的 `commentable` 关联会返回 `Post` 或者 `Video` 实例,这取决于评论所属的模型类型。
510603
511 #### 自定义多态关联的类型字段  
512   
513 默认,Laravel 会使用完全限定类名作为关联模型保存在多态模型上的类型字段值。比如,在上面的例子中,`Comment` 属于 `Post` 或者 `Video`,那么 `commentable_type`的默认值对应地就是 `App\Post` 和 `App\Video`。但是,你可能希望将数据库与程序内部结构解耦。那样的话,你可以定义一个「多态映射表」来指示 Eloquent 使用每个模型自定义类型字段名而不是类名:  
514   
515    use Illuminate\Database\Eloquent\Relations\Relation;  
516   
517    Relation::morphMap([  
518        'posts' => 'App\Post',  
519        'videos' => 'App\Video',  
520    ]);  
521   
522 你可以在 `AppServiceProvider` 中的 `boot` 函数中使用 `Relation::morphMap` 方法注册「多态映射表」,或者使用一个独立的服务提供者注册。  
523   
524604
525605<a name="many-to-many-polymorphic-relations"></a>
526 ### 多对多的多态关联
527 
528 #### 表结构
529 
530 除了传统的多态关联外,你也许也需要 “多对多” 的多条关联。举例而言,一个 `Post` 和 `Video` 模型共享一个 `Tag` 模型。使用多对多的多态关联将允许你去有一个在 `Video` 和 `Post` 之间共同使用的标签中有一个唯一性的单一列表。首先,让我来解读一下表结构:
 606### 多对多 (多态关联)
 607
 608#### 数据表结构
 609
 610「多对多」的多态关联比「一对一」和「一对多」的多态关联稍微复杂一些。举例而言,一个 `Post` 和 `Video` 模型共享一个 `Tag` 模型。使用多对多的多态关联将允许你去有一个在 `Video` 和 `Post` 之间共同使用一个唯一的标签列表。首先,让我们来看一下数据表结构:
531611
532612```
533613posts
 
550630
551631#### 模型结构
552632
553 接下来,我们要在模型上定义关联关系。 `Post` 和 `Video` 模型会有一个共同的 `tags` 方法,它们会被基础的模型的 `morphToMany` 方法调用:
 633接下来,我们要在模型上定义关联关系。 `Post` 和 `Video` 模型会有一个共同的 `tags` 方法,它们会被基础的模型的 `morphToMany` 方法调用:
554634
555635```php
556636<?php
 
623703   //
624704}
625705```
 706  
 707  
 708<a name="custom-polymorphic-types"></a>  
 709### 自定义多态类型  
 710  
 711默认,Laravel 会使用完全限定类名作为关联模型保存在多态模型上的类型字段值。比如,在上面的例子中,`Comment` 属于 `Post` 或者 `Video`,那么 `commentable_type`的默认值对应地就是 `App\Post` 和 `App\Video`。但是,你可能希望将数据库与程序内部结构解耦。那样的话,你可以定义一个「多态映射表」来指示 Eloquent 使用每个模型自定义类型字段名而不是类名:  
 712  
 713   use Illuminate\Database\Eloquent\Relations\Relation;  
 714  
 715   Relation::morphMap([  
 716       'posts' => 'App\Post',  
 717       'videos' => 'App\Video',  
 718   ]);  
 719  
 720你可以在 `AppServiceProvider` 中的 `boot` 函数中使用 `Relation::morphMap` 方法注册「多态映射表」,或者使用一个独立的服务提供者注册。  
 721  
 722  
626723<a name="querying-relations"></a>
627724## 查询关联
628725
 
672769}
673770```
674771
675 动态属性就像“懒加载”,也就是说当你确实会使用到它们的使用,它会自动进行加载。由于这一特性,开发者经常会使用到 [懒加载](#eager-loading) 去实现那些在获取到模型后必须要加载的关联模型。懒加载对 那些在模型上定了关联关系 SQL 查询上有了性能的提升,它们对 SQL 查询语句的执行次数有了明显的减少(也就是 n + 1性能问题)。
 772动态属性就像「懒加载」,也就是说当你确实会使用到它们的使用,它会自动进行加载。由于这一特性,开发者经常会使用到 [懒加载](#eager-loading) 去实现那些在获取到模型后必须要加载的关联模型。懒加载对 那些在模型上定了关联关系 SQL 查询上有了性能的提升,它们对 SQL 查询语句的执行次数有了明显的减少(也就是 n + 1性能问题)。
676773
677774<a name="querying-relationship-existence"></a>
678775### 查询关联关系是否存在
 
690787$posts = App\Post::has('comments', '>=', 3)->get();
691788```
692789
693 `has` 方法也可可以接受以 “.” 点形式的嵌套加载。举例来说,你要获取到至少包含一条评论和投票的博客:
 790`has` 方法也可可以接受以 「.」 点形式的嵌套加载。举例来说,你要获取到至少包含一条评论和投票的博客:
694791
695792```php
696793// 获取至少有一条评论的文章,并加载评论的投票信息
 
698795```
699796
700797如果你想要做更多特性,你还可以使用 `whereHas` 和 `
701 orWhereHas` 方法,在方法中,你可以指定 “where” 条件在你的 `has` 语句之中。这些方法允许你在关联查询之中添加自定义的条件约束,比如检查评论的内容:
 798orWhereHas` 方法,在方法中,你可以指定 「where」 条件在你的 `has` 语句之中。这些方法允许你在关联查询之中添加自定义的条件约束,比如检查评论的内容:
702799
703800```php
704801// 获取所有至少有一条评论的文章且评论内容以 foo 开头
 
723820})->get();
724821```
725822
726 你可能要使用 “.” 点符号去执行一个嵌套的加载。举例来说,如下语句,将会获取到所有文章,同时加载了那些没有被禁用的用户的文章评论:
 823你可能要使用 「.」 点符号去执行一个嵌套的加载。举例来说,如下语句,将会获取到所有文章,同时加载了那些没有被禁用的用户的文章评论:
727824
728825```php
729826$posts = App\Post::whereDoesntHave('comments.author', function ($query) {
 
771868<a name="eager-loading"></a>
772869## 懒加载
773870
774 当通过动态属性的方法去加载关联数据时,它已经是在 “懒加载” 了。也就是说,当你在未使用到该关联数据时,它其实是并没有查询数据的。然而, 当你在查询父级模型时, Eloquent 允许渴求式加载关联数据,渴求式加载避免了 N + 1 查询问题。为了说明 N + 1 的查询问题,思考 `Book` 模型关联了 `Auhtor` :
 871当通过动态属性的方法去加载关联数据时,它已经是在 「懒加载」 了。也就是说,当你在未使用到该关联数据时,它其实是并没有查询数据的。然而, 当你在查询父级模型时, Eloquent 允许渴求式加载关联数据,渴求式加载避免了 N + 1 查询问题。为了说明 N + 1 的查询问题,思考 `Book` 模型关联了 `Auhtor` :
775872
776873```php
777874<?php
 
832929
833930#### 嵌套式的渴求式加载
834931
835 实现渴求式加载也很简单,你可以使用 “.” 点语法去实现。譬如,我们需要加载所有的书籍,并且包含作者以及作者的联系方式。那么我们就可以这样写:
 932实现渴求式加载也很简单,你可以使用 「.」 点语法去实现。譬如,我们需要加载所有的书籍,并且包含作者以及作者的联系方式。那么我们就可以这样写:
836933
837934```php
838935$books = App\Book::with('author.contacts')->get();