Laravel5.1 模型--關聯關系(復雜)


關聯關系不只是我之前記錄的一對一,一對多,多對多這些相對簡單的關系,在實際開發中我們會遇到比較復雜的關系。

遠程一對多

遠程一對多聽着比較花哨 舉個栗子就很清楚了,比如用戶和文章是一對多的關系,國家和用戶也是一對多的關系,這樣看來 用戶是可以作為中間關聯對象來為國家和文章間建立一對多的關系,如果還是雲里霧里 就直接看代碼:

我們創建一個國家表:

php artisan make:migration create_countries_table --create=countries
    public function up()
    {
        Schema::create('countries', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

我們需要在user中在增加一列:

php artisan make:migration insert_country_id_intro_users --table=users
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->integer('country_id')->unsigned();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('country_id');
        });
    }

生成表后生成模型:

php artisan migrate
php artisan make:model Country

在tinker中生成兩條數據:

>>> $country = new App\Country();
=> App\Country {#708}
>>> $country->name = 'China';
=> "China"
>>> $country->save();
=> true
>>> $country2 = new App\Country();
=> App\Country {#709}
>>> $country2->name = 'America';
=> "America"
>>> $country2->save();
=> true

post文章的東西在簡單關聯中已經生成過了,就不在這說了。

現在來搞一搞遠程一對多,在Country中添加方法:

class Country extends Model
{
    public function posts()
    {
        return $this->hasManyThrough(Post::class,User::class);
    }
}

使用遠程一對多方法hasManyThrough(),其中第一個參數是需要關聯到的對象類名,第二個參數是中間關聯對象類名。

如果users表中表示用戶對應國家的字段不是county_id(假設為$country_id),並且posts表中表示文章所屬用戶的字段不是user_id(假設為$user_id),我們可以傳遞更多參數到hasManyThrough方法

    public function posts()
    {
        return $this->hasManyThrough('App\Models\Post','App\User',$country_id,$user_id);
    }

來看看測試代碼:

Route::get('/', function () {
    $country = \App\Country::find(1);
    $posts = $country->posts;
    echo $country->name . '作者的文章有:' . '<br />';
    foreach ($posts as $post){
        echo $post->title . '<br />';
    }
});

 

多態關聯

多態關聯用一個很簡單的例子就可以說清楚,比如評論,現在我們不只有文章這一個表了,還有一個視頻表,用戶可以評論文章也可以評論視頻,當然我們還需要一張評論表,但是一條評論可以屬於一篇文章 又可以屬於一段視頻,解決這個關系就需要用到多態關聯,在評論表添加item_id字段來存儲歸屬模型的ID,再添加一個item_type來存儲歸屬模型的類型 如:App\Post或App\Video,來吧 上代碼:

生成評論表和視頻表 並自行添加數據:

        Schema::create('comments', function (Blueprint $table) {
            $table->increments('id');
            $table->text('content');
            $table->integer('item_id')->unsigned();
            $table->integer('user_id')->unsigned();
            $table->string('item_type');
            $table->timestamps();
        });
        Schema::create('videos', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('content');
            $table->text('desc');
            $table->integer('user_id')->unsigned();
            $table->timestamps();
        });

創建Post和Video模型 並定義這個方法:

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

其中第一個參數是關聯模型類名,第二個參數是關聯名稱,即$item_id$item_type中的$item部分。當然也可以傳遞完整參數到morphMany方法:

$this->morphMany('App\Models\Comment',$item,$item_type,$item_id,$id);

如果需要也可以在Comment模型中定義相對的關聯關系獲取其所屬節點:

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

如果$item部分不等於item可以自定義傳入參數到morphTo

$this->morphTo($item,$item_type,$item_id);

OK,完成 測試代碼:

Route::get('/', function () {
    $video = \App\Video::find(1);
    echo $video->title . '所有的評論:'. '<br />';
    foreach ($video->comments as $comment){
        echo $comment->content . '<br />';
    }
});

 

多對多多態關聯

多態關聯之后還有一個更加復雜的關聯——多對多的多態關聯,這種關聯最常見的應用場景就是標簽,比如一篇文章對應多個標簽,一個視頻也對應多個標簽,同時一個標簽可能對應多篇文章或多個視頻,這就是所謂的“多對多多態關聯”。此時僅僅在標簽表tags上定義一個item_iditem_type已經不夠了,因為這個標簽可能對應多個文章或視頻,那么如何建立關聯關系呢,我們可以通過一張中間表taggables來實現:該表中定義了文章/視頻與標簽的對應關系。

 我們創建tag表和其對應的模型類:

    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

創建taggables表和對應的模型:

    public function up()
    {
        Schema::create('taggables', function (Blueprint $table) {
            $table->increments('id');
            // 對應着文章或視頻的id
            $table->integer('taggable_id')->unsigned();
            // 對應是文章類型還是視頻類型
            $table->string('taggable_type');
            // 對應是tag表的id
            $table->integer('tag_id')->unsigned();
            $table->timestamps();
        });
    }

我們在tags表添加幾條數據后繼續。

我們在Post模型和Video模型中定義方法:

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

其中第一個參數是關聯模型類名,第二個參數是關聯關系名稱,完整的參數列表如下:

$this->morphToMany('App\Models\Tag','taggable','taggable','taggable_id','tag_id',false);

其中第三個參數是對應關系表名,最后一個值若為true,則查詢的是關聯對象本身,若為false,查詢的是關聯對象與父模型的對應關系。

在Tag中定義相對應的關系:

    public function posts()
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }

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

其中第一個參數是關聯對象類名,第二個參數是關聯關系名稱,同理完整參數列表如下:

$this->morphedByMany('App\Models\Video','taggable','taggable','tag_id','taggable_id');

 

這樣關聯關系就已經對應好了,現在添加關聯表taggable數據:

>>> $tag = App\Tag::find(1);
=> App\Tag {#718
     id: 1,
     name: "php教程",
     created_at: "2017-03-30 13:05:07",
     updated_at: "2017-03-30 13:05:07",
   }
>>> $post = App\Post::find(1);
=> App\Post {#715
     id: 1,
     title: "Molestiae sit quos ut saepe nam ut itaque eos.",
     body: "Consequuntur odio dolores iure nihil distinctio. Sed neque eos aut voluptatem est sit quis quia. Inventore sint sint nesciunt libero dolores. Neque blanditiis sequi odio quia distinctio.",
     views: "0",
     user_id: 1,
     created_at: "2017-03-26 17:25:47",
     updated_at: "2017-03-26 17:25:47",
   }
>>> $post->tags()->save($tag);
=> App\Tag {#718
     id: 1,
     name: "php教程",
     created_at: "2017-03-30 13:05:07",
     updated_at: "2017-03-30 13:05:07",
   }

測試代碼:

Route::get('/', function () {
    $post = App\Post::find(1);
    $tags = $post->tags;
    dd($tags);
});

 


免責聲明!

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



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