laravel 關聯模型 多態關系


laravel 關聯模型 多態關系

一對一(多態)

note

1個關聯上從屬於多個模型,如:博客post和用戶user共享1個關聯圖片image

1篇博客擁有1張主圖
1個用戶擁有1個頭像

graph LR image(圖片) image --> |imageable_id=post.id<br>imageable_type=App\Model\Post| post(博客) image --> |imageable_id=user.id<br>imageable_type=App\Model\User| user(用戶)

table

post ( id, title, content)
user ( id, name )
image ( id, imageable_id, imageable_type, url)
#`imageable_id`關聯表ID,`imageable_type`關聯模型類名

model

class Image extends Model
{
    const TABLE = 'image';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','imageable_id','imageable_type','url','created_at','updated_at' ];

    public function imageable()
    {
        return $this->morphTo();
    }
}
class Post extends Model
{
    const TABLE = 'post';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','title','content','created_at','updated_at' ];

    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}
class User extends Model
{
    const TABLE = 'user';
    protected $table = self::TABLE;
    
    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

code

查詢關聯

image表

ID imageable_id imageable_type url

1 1 App\Model\Post xxx
2 1 App\Model\User xxxx

Post::with('image')->find(1)->toArray();
User::with('image')->find(1)->toArray();

#反向查詢
Image::with('imageable')->find(1)->toArray();

添加關聯

#非關聯添加,直接新增關聯表
Image::create(['imageable_id' => 2,'imageable_type' => Post::class,'url' => 'xxx']);

#關聯添加,不用給關聯字段賦值,推薦使用
$post = Post::find(1);
$post->image()->create(['url'=>'x']);

更新關聯

#非關聯更新,直接更新關聯表對應記錄
Image::where(['imageable_id'=>2,'imageable_type'=>Post::class)->update(['url'=>'new url']);
              
#關聯更新,推薦使用
$post = Post::find(1);
$post->image()->update(['url'=>'new url']);
#update針對‘一對一’,‘一對多’應該刪除對應的所有關聯再新增

刪除關聯

#非關聯刪除,直接刪除關聯表對應記錄
Image::where(['imageable_id'=>2,'imageable_type'=>Post::class)->delete();

#關聯刪除,推薦使用
$post = Post::find(1);
$post->image()->delete();

一對多(多態)

note

1個關聯上從屬於多個模型,如:文章article和視頻video共享1個關聯評論comment

1篇文章擁有多個評論
1個視頻擁有多個評論

graph LR comment(評論) comment --> |commentable_id=article.id<br>commentable_type=App\Model\Article| article(文章) comment --> |commentable_id=video.id<br>commentable_type=App\Model\Video| video(視頻)

table

article ( id, name )
video ( id, title, url )
comment ( id, commentable_id, commentable_type, content)
#`commentable_id`關聯表ID,`commentable_type`關聯模型類名

model

class Comment extends Model
{
    const TABLE = 'comment';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','commentable_id','commentable_type','content','created_at','updated_at' ];

    public function commentable()
    {
        return $this->morphTo();
    }
}
class Article extends Model
{
    const TABLE = 'article';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function comments()
    {
        return $this->morphMany(Comment::class,'commentable');
    }
}
class Video extends Model
{
    const TABLE = 'video';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','title','url','created_at','updated_at' ];

    public function comments()
    {
        return $this->morphMany(Comment::class,'commentable');
    }
}

code

查詢關聯

Article::with('comments')->find(1)->toArray();
Video::with('comments')->find(1)->toArray();

#反向查詢
Comment::with('commentable')->find(1)->toArray();

高級1點的查詢

Article::has('comments')->get()->toArray();	#查詢至少1條評論的文章
Article::has('comments','>=',5)->get()->toArray();	#查詢至少5條評論的文章

#查詢評論包含‘xx’的文章
Article::whereHas('comments', function (Builder $query) {
            $query->where('content', 'like', '%xx%');
        })->get()->toArray();

#查詢評論 包含‘xx’ & 至少5條評論 的文章
Article::whereHas('comments', function (Builder $query) {
            $query->where('content', 'like', '%xx%');
        }, '>=', 5)->get()->toArray();

添加關聯

$article = Article::find(3);

$article->comments()->save(new Comment(['content'=>'new new']))
$article->comments()->create(['content' => 'good good study']);

$article->comments()->createMany([
            ['content' => 'good good study'],
            ['content' => 'day day up']
        ]);

刪除關聯

$article = Article::find(3);
$article->comments()->where('id',7)->delete();	#刪除關聯表comment id=7記錄
$article->comments()->delete();	#刪除所有關聯

更新關聯

#更新指定評論
$article = Article::find(3);
$article->comments()->where('id',6)->update(['content'=>'new contetn']);

#先刪除所有關聯,再添加關聯。

多對多(多態)

note

使用多對多多態關聯允許使用一個唯一標簽在博客文章和視頻間共享。

1篇文章對應多個標簽,1個標簽對應多篇文章
1個視頻對應多個標簽,1個標簽對應多個視頻
1個標簽既可以是文章的標簽,也是視頻的標簽,即文章和視頻共享同1個標簽

graph LR tag(標簽) --> |tag_id| tagable(關聯) tagable --> |tagable_id=article.id<br>tagable_type=App\Model\Article| article(文章) tagable --> |tagable_id=video.id<br>tagable_type=App\Model\Video| video(視頻)

table

article ( id, name )
video ( id, title, url )
tag ( id, name )
tagable ( tag_id, tagable_id, tagable_type )
#`tagable_id`關聯表ID,`tagable_type`關聯模型類名

model

class Tag extends Model
{
    const TABLE = 'tag';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];


    public function articles()
    {
        return $this->morphedByMany(Article::class, 'tagable', Tagable::TABLE);
    }

    public function videos()
    {
        return $this->morphedByMany(Video::class, 'tagable', Tagable::TABLE);
    }
}

class Tagable extends Model
{
    const TABLE = 'tagable';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','tag_id','tagable_id','tagable_type','created_at','updated_at' ];
}
class Article extends Model
{
    const TABLE = 'article';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','name','created_at','updated_at' ];

    public function tags()
    {
        return $this->morphToMany(Tag::class, 'tagable', Tagable::TABLE);
    }
}
class Video extends Model
{
    const TABLE = 'video';
    protected $table = self::TABLE;

    protected $fillable = [ 'id','title','url','created_at','updated_at' ];

    public function tags()
    {
        return $this->morphToMany(Tag::class, 'tagable', Tagable::TABLE);
    }
}

注意

morphToMany($related, $name, $table = null)
morphedByMany($related, $name, $table = null)
//$table=null,默認為$name + s

code

查詢關聯

Article::with('tags')->find(1)->toArray();
Video::with('tags')->find(1)->toArray();

//反向查詢
Tag::with('articles')->find(1)->toArray();

添加關聯

$article->tags()->create(['name' => '神話']);
#新增記錄,標簽表tag & 關聯表tagable,同時新增

$article->tags()->attach(4);
#新增記錄,僅新增關聯表tagable

$article->tags()->attach([
    7 => ['created_at' => '2020-07-08 11:01:27'],
    8 => ['created_at' => '2020-07-08 11:01:27'],
]);

同步關聯

$article = Article::find(1);
$article->tags()->sync([1,3]);
//sync(),等同於,新增或保留1,3,刪除其他

刪除關聯

$article = Article::find(1);
$article->tags()->detach([1,3]);
//detach($tagIds); $tagIds: 數組,要刪除的id
//  為null即不傳參數時,刪除對應的所有關聯


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM