首页 » Web技术 » Laravel » 正文

[Laravel 5 教程学习笔记] 十九、多对多关系-标签

当我们创建一个博客程序的时候,我们当然需要能够撰写博客并发布,另外还要给出一种来关联它们的方法。我们可以使用查找功能,但查找功能留到以后再做,这里先介绍使用标签的方式。比如我们给一篇博客添加了标签“PHP”,那么浏览这篇博客的用户可能会想浏览所有带有该标签的博客,这应该如何实现呢?换句话说,应该如何设计数据库与Eloquent模型呢?这就是这一节所要介绍的多对多关系。

在介绍前可以先复习以下第十四节介绍的《Eloquent关系》,其中介绍了一对一与一对多的关系。

打开 /app/Article.php ,添加多对多关系方法:

    public function tags(){
        return $this->belongsToMany('App\Tag');
    }

然后用命令行创建标签的Eloquent Model:

D:\wamp\www\laravel5>php artisan make:model Tag
Model created successfully.
Created Migration: 2015_07_25_210033_create_tags_table

这条命令会在 /app/ 下生成一个 Tag.php 文件,并且在 /database/migrations/ 下生成一个类似 XXX_create_tags_table.php 的数据库迁移文件,如果没有生成数据库迁移文件的话,可以通过下面的命令行来创建:

D:\wamp\www\laravel5>php artisan make:migration create_tags_table --create=tags

接着修改刚刚生成的数据库迁移文件:

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

        Schema::create('article_tag', function(Blueprint $table){
            $table->integer('article_id')->unsigned()->index();
            $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');

            $table->integer('tag_id')->unsigned()->index();
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');

            $table->timestamps();

        });
    }


    public function down()
    {
        Schema::drop('tags');
        Schema::drop('article_tag');
    }
注:上面表 article_tag 的表名命名方法为取两个关联表的表名单数形式,然后按首字母升序排序,用下划线 _ 连接。如表 usersroles 的中间表可以命名为 role_user

接着在命令行下进行数据库迁移:

D:\wamp\www\laravel5>php artisan migrate
Migrated: 2015_07_25_210033_create_tags_table

App/Tag.php 中添加多对多关系方法:

    public function articles(){
        return $this->belongsToMany('App\Article');
    }

下面用 php artisan tinker 命令行工具来介绍多对多关系,这样看起来更加清楚。

D:\wamp\www\laravel5>php artisan tinker
Psy Shell v0.4.1 (PHP 5.5.12 ΓÇö cli) by Justin Hileman
>>> $tag = new App\Tag; //创建一个新的tag
=> <App\Tag #000000003d1f1f780000000013a9ed91> {}
>>> $tag->name = 'PHP';
=> "PHP"
>>> $tag->save();  //保存tag
=> true
>>> App\Tag::all()->toArray();  //获取所有 tags
=> [
       [
           "id"         => 1,
           "name"       => "PHP",
           "created_at" => "2015-07-25 21:29:45",
           "updated_at" => "2015-07-25 21:29:45"
       ]
   ]
>>> App\Tag::lists('name');  //列出所有tags的名称
=> [
       "PHP"
   ]

下面来关联 文章 与 标签:

>>> $article = App\Article::first(); //获取第一篇博客
=> <App\Article #000000003d1f1f6b0000000013a9ed91> {
       id: 1,
       user_id: 1,
       title: "This is the first article",
       body: "This is the first article content.",
       created_at: "2015-07-25 21:18:08",
       updated_at: "2015-07-25 21:18:08",
       published_at: "2015-07-25 00:00:00",
       excerpt: null
   }
>>> $article->tags()->attach(1);  // 把 ID 为 1 的tag关联到刚刚获取的博客
=> null

这时查看数据库,发现虽然标签与博客关联上了(有的可能是直接报错,没有添加成功),但是创建时间与修改时间却都是空的。这时需要修改 Article.php 中刚刚添加的 tags() 方法:

    public function tags(){
        return $this->belongsToMany('App\Tag')->withTimestamps();
    }

这时,退出上次的命令行并重新打开(否则刚刚的修改不生效):

D:\wamp\www\laravel5>php artisan tinker
Psy Shell v0.4.1 (PHP 5.5.12 ΓÇö cli) by Justin Hileman
>>> $article = App\Article::first();
=> <App\Article #000000000fac5aa70000000016f5b020> {
       id: 1,
       user_id: 1,
       title: "This is the first article",
       body: "This is the first article content.",
       created_at: "2015-07-25 21:18:08",
       updated_at: "2015-07-25 21:18:08",
       published_at: "2015-07-25 00:00:00",
       excerpt: null
   }
>>> $article->tags()->attach(1);
=> null

这时再次查看数据库,可以看到已经关联成功了。

laravel-many-to-many

接着通过命令行来查看多对多关系,获取与给定博客关联的标签:

>>> $article->toArray();
=> [
       "id"           => 1,
       "user_id"      => 1,
       "title"        => "This is the first article",
       "body"         => "This is the first article content.",
       "created_at"   => "2015-07-25 21:18:08",
       "updated_at"   => "2015-07-25 21:18:08",
       "published_at" => "2015-07-25 00:00:00",
       "excerpt"      => null
   ]
>>> $article->tags->toArray();  //获取博客的所有标签
=> [
       [
           "id"         => 1,
           "name"       => "PHP",
           "created_at" => "2015-07-25 21:29:45",
           "updated_at" => "2015-07-25 21:29:45",
           "pivot"      => [
               "article_id" => 1,
               "tag_id"     => 1,
               "created_at" => "2015-07-25 21:38:00",
               "updated_at" => "2015-07-25 21:38:00"
           ]
       ]
   ]
>>> $article->toArray();  //已经关联标签的博客数据
=> [
       "id"           => 1,
       "user_id"      => 1,
       "title"        => "This is the first article",
       "body"         => "This is the first article content.",
       "created_at"   => "2015-07-25 21:18:08",
       "updated_at"   => "2015-07-25 21:18:08",
       "published_at" => "2015-07-25 00:00:00",
       "excerpt"      => null,
       "tags"         => [
           [
               "id"         => 1,
               "name"       => "PHP",
               "created_at" => "2015-07-25 21:29:45",
               "updated_at" => "2015-07-25 21:29:45",
               "pivot"      => [
                   "article_id" => 1,
                   "tag_id"     => 1,
                   "created_at" => "2015-07-25 21:38:00",
                   "updated_at" => "2015-07-25 21:38:00"
               ]
           ]
       ]
   ]
>>> $article->tags->lists('name'); //列出该博客所有标签的名称
=> [
       "PHP"
   ]

现在进行反向操作,获取与给定标签关联的博客:

>>> $tag = App\Tag::first();
=> <App\Tag #0000000051a0274c0000000008cd8bdd> {
       id: 1,
       name: "PHP",
       created_at: "2015-07-25 21:29:45",
       updated_at: "2015-07-25 21:29:45"
   }
>>> $tag->articles->toArray();
=> [
       [
           "id"           => 1,
           "user_id"      => 1,
           "title"        => "This is the first article",
           "body"         => "This is the first article content.",
           "created_at"   => "2015-07-25 21:18:08",
           "updated_at"   => "2015-07-25 21:18:08",
           "published_at" => "2015-07-25 00:00:00",
           "excerpt"      => null,
           "pivot"        => [
               "tag_id"     => 1,
               "article_id" => 1
           ]
       ]
   ]

可以看到,也获取成功了。本节完!


该篇属于专题:《Laravel 5 基础视频教程学习笔记

本文共 2 个回复

  • dodo 2015/11/12 15:38

    我才发现, 除了前2章,其他和 https: // laracasts.com/series/laravel-5-fundamentals 都是一样的.... :eek:

发表评论