一些关于laravel多态(Polymorphic Relations)的记录

最近在做项目遇到多态关联的问题,但是以为没有必要使用多态,按照以往的开发方式可以解决,后来发现这样的实现是有点问题的,并且在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就是外键.

参考Laravel Eloquent Relationships

点赞