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);
});
时间: 2024-10-08 09:30:19

Laravel5.1 模型--关联关系(复杂)的相关文章

Laravel5.1 模型 --一对一关系

这篇文章主要记录模型的一对一关系,关联关系是Model的一种非常方便的功能. 1 实现一对一关系 1.1 准备工作 首先我们需要创建两张表和对应的两个模型,第一个模型是用户表,第二个模型是账号表. 这里 我们的逻辑是:一个用户信息下只能有一个账号,一个账号只能被一个用户所拥有,这就是一对一关系. 1.1.1 用户信息表 生成模型和迁移文件: php artisan make:model UserInfo -m 编写迁移文件(表规格): public function up() { Schema:

Laravel5.1 模型--ModelFactory

今天要说的是模型工厂,它是可以快速生成一些测试数据的东西,之前我们介绍过Seeder,当我们使用模型访问数据时 可以用模型工厂搭配Seeder使用. 1 编写一个ModelFactory ModelFactory的路径在 database/factories/ 下: // 这是系统自带的工厂 $factory->define(App\User::class, function ($faker) { return [ 'name' => $faker->name, 'email' =>

Laravel5.1 模型 --多对多关系

多对多关系也是很常用的一种关系,比如一篇文章可以有多个标签,一个标签下也可以有多篇文章,这就是一个典型的多对多的关系. 1 实现多对多关系 多对多关系我们需要三张表,一张是文章另一张是标签,第三章表是它们的中间表 因为多对多关系需要抽离成两个一对多关系嘛. 1.1 文章结构 public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table

Laravel5.1 模型 --软删除

软删除是比较实用的一种删除手段,比如说 你有一本账 有一笔记录你觉得不对给删了 过了几天发现不应该删除,这时候软删除的目的就实现了 你可以找到已经被删除的数据进行操作 可以是还原也可以是真正的删除. 1 普通删除 在软删除之前咱先看看普通的删除方法: 1.1 直接通过主键删除 public function getDelete() { Article::destroy(1); Article::destroy([1,2,3]); } 1.2 获取model后删除 public function

Laravel5.1 模型初探

Laravel的模型也是访问数据库的,它更加面向对象,一个模型对应着一张表 我们可以使用模型对数据做一些增删改查的操作. 1 创建模型 创建模型是可以使用Artisan控制台的: php artisan make:model Article 一般我比较喜欢连带着migration一起生成: php artisan make:model Article -m ↑ 执行了上面的Artisan命令后 我们就可以在 /app 下找到我们刚刚创建的模型了,顺便也生成好了migration. 2 模型常用属

Laravel5.1 模型--删除

今天我们来看看如何删除数据 delete删除模型 获取到模型,执行delete方法就好: public function destroy($id) { $article = Article::findOrFail($id); if ($article->delete()){ echo '删除成功'; }else{ echo '删除失败'; } } delete方法会返回一个bool值. destory删除模型 相比较delete而言更加简洁,只要你知道id字段就可以使用: $delete = \

Laravel5.1 模型--查询作用域

所谓的查询作用域就是允许你自定义一个查询语句 把它封装成一个方法. 1 定义一个查询作用域 定义查询作用域就是在模型中声明一个scope开头的方法: public function scopeHotArticle($query) { return $query->orderBy('comment_count','desc')->first(); } 然后可以这样使用: public function getIndex() { $hot = Article::hotArticle(); dd($

Laravel5.1 模型--查询

前两天病了..一直没写笔记,今儿个来看看Model在实际开发中的一些简单使用,首先 我们来为今天的学习做个铺垫,也当做复习了 准备工作 1.生成表 php artisan make:migration create_articles_table --create=articles <?php use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateArt

laravel 中with关联查询限定查询字段

学习了下laravel5.6框架,果然很优雅,比如ActiveJieSuan model中作如下关联:(laravel模型关联关系可以查看https://laravelacademy.org/post/8867.html) 只需在ActiveJieSuan 模型中设定 protected $with = ['user','actice']; 那么查询ActiveJieSuan就能自动关联上users,actice_contents表. 如果要限定关联查询的字段,可以如下写法: ActiveJie