多态关联

Laravel Eloquent ORM 多态关联

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

表结构:

posts

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

vidoes

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

comments

id(自增主键)body(主体内容)commentable_idcommentable_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

<?php

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

<?php

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模型

<?php

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模型

<?php

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模型

<?php

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()函数

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

<?php

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'.'<br>';
   foreach($post->comments as $c){
       echo '<li>'.$c->body.'</li>'.'<br>';
   }

   echo 'video'.'<br>';
   foreach($video->comments as $c){
       echo '<li>'.$c->body.'</li>'.'<br>';
   }

   echo $comment->commentable_type;
   echo '<br><pre>';
   var_dump($comment->commentable);
});

查看页面显示即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值