首页 > 代码库 > Laravel5.1 模型--关联关系(复杂)

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);
});

 

Laravel5.1 模型--关联关系(复杂)