laravel中的模型的多态关系

多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。

多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果.

什么时候会使用多态呢.

想象一下使用您应用的用户可以「评论」文章和视频。

一篇文章(视频)有多个评论,一个评论属于一篇文章(视频). 这里是两个一对多的关联关系.(

评论的操作是相同的,操作的对象是不同的,

使用多态关联,您可以用一个comments 表同时满足这两个使用场景

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

comments 表中有两个需要注意的重要字段 commentable_id 和 commentable_type。commentable_id 用来保存文章或者视频的 ID 值,而 commentable_type 用来保存所属模型的类名。commentable_type 是在我们访问 commentable 关联时, 让 ORM 确定所属的模型是哪个「类型」。

模型结构#

接下来,我们来看看创建这种关联所需的模型定义:

下面的morphMany;可以理解为和多个对象有hasMany的关系.

morphTo可以理解为从多个对象中找到一个属于我的对象.

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

}

}

获取多态关联#

一旦您的数据库表准备好、模型定义完成后,就可以通过模型来访问关联了。例如,我们只要简单地使用 comments动态属性,就可以获得某篇文章下的所有评论:

$post = App\Post::find(1);

foreach ($post->comments as $comment) {

//

}您也可以在多态模型上,通过访问调用了 morphTo 的关联方法获得多态关联的拥有者。在当前场景中,就是 Comment 模型的 commentable 方法。所以,我们可以使用动态属性来访问这个方法:

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

$commentable = $comment->commentable;

Comment 模型的 commentable 关联会返回 Post 或者 Video 实例,这取决于评论所属的模型类型(commentable_type)。

自定义多态关联的类型字段#

默认,Laravel 会使用完全限定类名作为关联模型保存在多态模型上的类型字段值。比如,在上面的例子中,Comment 属于 Post 或者 Video,那么 commentable_type的默认值对应地就是 App\Post 和 App\Video。但是,您可能希望将数据库与程序内部结构解耦。那样的话,你可以定义一个「多态映射表」来指示 Eloquent 使用每个模型自定义类型字段名而不是类名:

use Illuminate\Database\Eloquent\Relations\Relation;

Relation::morphMap([

'posts' => 'App\Post',

'videos' => 'App\Video',

]);

您可以在 AppServiceProvider 中的 boot 函数中使用 Relation::morphMap 方法注册「多态映射表」,或者使用一个独立的服务提供者注册。

在这里存储的commentable_type一般情况下为表名.这样看起来,语义明确.表和模型相对应.

多维多态关系:

文章和标签之间的关系.

视频和标签的关系.

文章和标签之间的关系是多对多的关系.视频和标签之间的关系也是多对多的关系.在文章和标签,视频和标签的模型之中都需要定义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

模型结构#

接下来,我们准备在模型上定义关联关系。Post 和 Video 两个模型都有一个 tags 方法,方法内部都调用了 Eloquent 类自身的 morphToMany 方法:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model

{ /** * 获得此文章的所有标签。 */

public function tags()

{

return $this->morphToMany('App\Tag', 'taggable');

}

}

定义反向关联#

接下里,在 Tag 模型中,您应该为每个关联模型定义一个方法。在这个例子里,我们要定义一个 posts 方法和一个 videos 方法:

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

}

}

获取关联#

一旦您的数据库表准备好、模型定义完成后,就可以通过模型来访问关联了。例如,我们只要简单地使用 tags 动态属性,就可以获得某篇文章下的所有标签:

$post = App\Post::find(1);

foreach ($post->tags as $tag) {

//

}您也可以在多态模型上,通过访问调用了 morphedByMany 的关联方法获得多态关联的拥有者。在当前场景中,就是 Tag 模型上的 posts 方法和 videos 方法。所以,我们可以使用动态属性来访问这两个方法:

$tag = App\Tag::find(1);

foreach ($tag->videos as $video) {

//}

日记本

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

赞赏支持
被以下专题收入,发现更多相似内容