多态关联允许一个模型在单个关联下属于多个不同模型
表结构:
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
列对应 posts 或 vidoes 的 id 值;commentable_type
列对应所属模型的数据表名
数据表中,本人设置了
软删除
功能,即 deleted_at 字段,对于数据库其重要性就在于数据,因此添加此功能是必要的,当然这软删除
不是说你不能删除数据,而是给数据库的删除操作提供一个容错性
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
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模型
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 ! 现在多态关联关系已经建立完毕,就等着我们去测试了
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);
});
查看页面显示即可