最近在做项目遇到多态关联的问题,但是以为没有必要使用多态,按照以往的开发方式可以解决,后来发现这样的实现是有点问题的,并且在Laravel上似乎不是很推荐,于是使用了Laravel的多态。问题详情
问题一,多态关联的时候关联的type字段是字符串,存储的内容是App\User
这样的类名,耦合比较大,而且不是很合理,如何修改?
我的项目中使用的是Int型的类型Id作为区分,所以首先引入Illuminate\Database\Eloquent\Relations\Relation
在类的外部增定义一个映射,使用的时候一定要注意定义的位置,因为在官方文档中更推荐在AppServiceProvider
中去注册,但是很多时候我们这个标签的id是会重复的,不方便全局去注册.
<?php
namespace App;
...
use Illuminate\Database\Eloquent\Relations\Relation;
...
class Tag extends Model{
...
public function boot()
{
Relation::morphMap([
1 => Apple::class,
2 => Orange::class,
]);
parent::boot();
}
public function good()
{
return $this->morphTo('owner','owner','owner_id');
}
...
}
在对应的Apple
模型里面我们需要注意的是要使用morphOne
,并且留意它的第二个参数要和我们上面的函数名一致。
class Apple extends Model{
...
public function tag()
{
return $this->morphOne(Tag::class, 'good', 'owner', 'owner_id');
}
...
}
问题二,morphTo
的参数到底是什么意思?
我在使用的时候也一直很疑问,文档上面也没有做说明,于是自己研究了一下源码.
/**
* Define a polymorphic, inverse one-to-one or many relationship.
*
* @param string $name
* @param string $type
* @param string $id
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function morphTo($name = null, $type = null, $id = null)
{
// If no name is provided, we will use the backtrace to get the function name
// since that is most likely the name of the polymorphic interface. We can
// use that to get both the class and foreign key that will be utilized.
$name = $name ?: $this->guessBelongsToRelation();
list($type, $id) = $this->getMorphs(
Str::snake($name), $type, $id
);
// If the type value is null it is probably safe to assume we're eager loading
// the relationship. In this case we'll just pass in a dummy query where we
// need to remove any eager loads that may already be defined on a model.
return empty($class = $this->{$type})
? $this->morphEagerTo($name, $type, $id)
: $this->morphInstanceTo($class, $name, $type, $id);
}
第一个参数我测试了以后发现只是作为声明关系用的,相当于给关系起了个名字而已.影响不是很大.第二个type
对应的就是供系统来做关联区分的字段,通过这个字段系统来选择需要关联性模型,最后一个字段id
就是外键.