多态关联

Laravel Eloquent ORM 多态关联

多态关联允许一个模型在单个关联下属于多个不同模型

表结构:

posts

id(自增主键) title(标题) body(主体内容)

vidoes

id(自增主键) title(标题) url(播放地址)

comments

id(自增主键) body(主体内容) commentable_id commentable_type
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 列对应 postsvidoes 的 id 值;commentable_type 列对应所属模型的数据表名

数据表中,本人设置了软删除功能,即 deleted_at 字段,对于数据库其重要性就在于数据,因此添加此功能是必要的,当然这软删除不是说你不能删除数据,而是给数据库的删除操作提供一个容错性

1.创建并编写执行迁移文件

php artisan make:migration pvc



use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->softDeletes();
            $table->increments('id');
            $table->timestamps();

            $table->string('title',255)->notNull();
            $table->text('body')->notNull();
        });

        Schema::create('videos', function (Blueprint $table) {
            $table->softDeletes();
            $table->increments('id');
            $table->timestamps();

            $table->string('title',255)->notNull();
            $table->string('url',255)->notNull();
        });

        Schema::create('comments', function (Blueprint $table) {
            $table->softDeletes();
            $table->increments('id');
            $table->timestamps();

            $table->text('body')->notNull();
            $table->integer('commentable_id')->notNull();
            $table->string('commentable_type',64)->notNull();
        });
    }
    public function down()
    {
        Schema::dropIfExists('posts');
        Schema::dropIfExists('videos');
        Schema::dropIfExists('comments');
    }
}

执行迁移文件:`php artisan migrate

2.生成并测试种子文件

php artisan make:seeder PVC_table_seeder



use Illuminate\Database\Seeder;

class PVC_table_seeder extends Seeder
{
    public function run()
    {
        $faker=\Faker\Factory::create('en_UK');

        $Vdata=[];
        for ($i=0; $i < 10; $i++) { 
            $Vdata[]=[
                'title'     =>      $faker->title,
                'url'       =>      $faker->url,
                'created_at'=>      date('Y-m-d H:i:s',time()),
            ];
        }
        DB::table('videos')->insert($Vdata);

        $Pdata=[];
        for ($i=0; $i < 10; $i++) { 
            $Pdata[]=[
                'title'     =>      $faker->title,
                'body'       =>     $faker->text,
                'created_at'=>      date('Y-m-d H:i:s',time()),
            ];
        }
        DB::table('posts')->insert($Pdata);

        $Cdata=[];
        for ($i=0; $i < 50; $i++) { 
            $Cdata[]=[
                'body'       =>      $faker->text,
                'commentable_id'=>   mt_rand(1,10),
                'commentable_type'=> mt_rand(1,2),
                //这里生成随机数,1代表videos ; 2代表posts, 生成测试数据后手动在数据表中改成对应字符串
                'created_at'=>      date('Y-m-d H:i:s',time()),
            ];
        }
        DB::table('comments')->insert($Cdata);
    }
}

执行种子文件:php artisan db:seed –class=PVC_table_seeder

修改数据库中 commentable_type字段:

mysql-> update comments set commentable_type='videos' where commentable_type=1;
mysql-> update comments set commentable_type='posts' where commentable_type=2;

如果你不想这么麻烦的步骤,可以直接下载 pvc.sql 导入MySQL数据库中

数据表有来,接下来就是Eloquent模型

3.模型创建和关联

php artisan make:model Duotai/Comment
php artisan make:model Duotai/Post
php artisan make:model Duotai/Video

Comment模型



namespace App\Duotai;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Comment extends Model
{
    use softDeletes;
    protected $dates = ['deleted_at'];
    public $table='comments';

    public function commentable(){
        return $this->morphTo();
    }
}

Post模型



namespace App\Duotai;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
    use softDeletes;
    protected $dates = ['deleted_at'];

    const TABLE = 'posts';
    protected $table = self::TABLE;

    public function comments(){
        return $this->morphMany('\App\Duotai\comment','commentable');
    }
}

Video模型



namespace App\Duotai;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Video extends Model
{
    use softDeletes;
    protected $dates = ['deleted_at'];

    const TABLE = 'videos';
    protected $table = self::TABLE;

    public function comments(){
        return $this->morphMany('\App\Duotai\comment','commentable');
    }
}

接下来就是很重要的一步:AppServiceProvider服务提供者中注册morphMap()函数

如果需要的话,也可以创建一个独立的服务提供者来实现这一功能



namespace App\Providers;

use Illuminate\Support\ServiceProvider;

use App\Duotai\Post;
use App\Duotai\Video;
use Illuminate\Database\Eloquent\Relations\Relation;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {

        $this->bootEloquentMorphs();
    }
    private function bootEloquentMorphs()
    {
        Relation::morphMap([
            Post::TABLE => Post::class,
            Video::TABLE => Video::class,
        ]);
    }

    public function register()
    {
        //
    }
}

OK ! 现在多态关联关系已经建立完毕,就等着我们去测试了

4.测试

Route::get('/test',function(){
   $post=\App\Duotai\Post::find(1);
   $comment=\App\Duotai\Comment::find(1);
   $video=\App\Duotai\Video::find(1);
   echo 'post'.'
'
; foreach($post->comments as $c){ echo '
  • '.$c->body.'
  • '
    .'
    '
    ; } echo 'video'.'
    '
    ; foreach($video->comments as $c){ echo '
  • '.$c->body.'
  • '
    .'
    '
    ; } echo $comment->commentable_type; echo '
    ';
       var_dump($comment->commentable);
    });

    查看页面显示即可

    你可能感兴趣的:(多态关联)