前言
上一节,我们对 flash message 的使用做一个讲解,了解到什么是 flash message,而且会进行简单的使用。本节,我们对数据库多对多的形式,以文章 tags 作为例子进行讲解。
说明
开发环境:Windows 7
Laravel 版本: 5+
IDE: Phpstorm
数据库在,之前我们就对 Laravel 的Eloquent 和Migration 做过两节介绍,而且在Relationships 讲过数据表之间的外键关系,那也是基本的一对多。
本节我们对数据库中的多对多进行一个讲解,而且所举的例子就是 tags ,文章标签。
现在咱们博客的基本功能已经有了,写文章,发表文章等。但是随着文章越来越多,文章的筛选和管理就成了问题,要是能有 tag 标记每篇文章的关键词,这对文章的管理将是一个很大的改善。
下面我们就来看一下 Eloquent 是怎么实现给文章 tagging 的。
打开的 Article.php ,还记得当初我们为每篇文章(Article)关联作者(User)是在哪个方法吗?算了,你也回答不了,就在最下面的 user() 方法,里面写了一句 belongsTo 就指明了文章所属。该语句与 hasMany 是相对的,文章只能 belongsTo 一个作者,但是一名作者可以 hasMany 文章,就是这么个关系。
但是在 tag 这里,belongsTo 和 hasMany 就有点讲不通了,一篇文章不能只 belongsTo 一个 tag ,应该是 belongsToMany tags 才通顺。
所在在 user() 方法下面再价一个 tags() 方法,如下所示:
public function tags(){ return $this->belongsToMany('App\Tag');}
下面呢,我们去创建一个 Tag Eloquent model吧。
在命令行下输入命令:php artisan make:model Tag。
再在命令行下输入命令: php artisan make:migration create tagtable –create=tags
打开这个 create tagtable.php ,在这里创建 tag 表的一些属性或者说列:
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');}
之所以还同时创建一个 pivot table (即“ article_tag ”表),就是为了相当于一个快速查找表,能把 article 和 tag 联系在一张表中,方便查取。
接下来对 migration 进行执行,在命令行中执行:php artisan migrate
接下来打开 Tag.php,刚创建的。
既然 tag 和 Article 是多对多的关系,那么在 Tag model 类中也应有一个指向 article 的方法:
public function articles(){ return $this->belongsToMany('App\Article'); |}
保存后,打开命令行,通过 tinker 来验证是否成功:php artisan tinker
>>> $tag = new App\Tag;=> App\Tag {#646}>>> $tag->name='personal';=> "personal">>> $tag->save();=> true>>> App\Tag::all()->toArray();=> [ [ "id" => 1, "name" => "personal", "created_at" => "2016-04-30 13:48:49", "updated_at" => "2016-04-30 13:48:49", ], ]
下面我们尝试关联一下这两个表。
在 tinker 模式下:
>>> App\Tag::all()->toArray();=> [ [ "id" => 1, "name" => "personal", "created_at" => "2016-04-30 13:48:49", "updated_at" => "2016-04-30 13:48:49", ], ]>>> $article=App\Article::first();=> App\Article {#659 id: "1", user_id: "1", created_at: "2016-03-20 15:05:18", updated_at: "2016-03-20 15:05:18", title: "谭晓龙创建的文章", body: "真的是", published_at: "2016-03-28 00:00:00", }>>> $article->toArray();=> [ "id" => 1, "user_id" => "1", "created_at" => "2016-03-20 15:05:18", "updated_at" => "2016-03-20 15:05:18", "title" => "谭晓龙创建的文章", "body" => "真的是", "published_at" => "2016-03-28 00:00:00", ]>>> $article->tags()->attach(1);Illuminate\Database\QueryExceptionwithmessage 'SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: article_tag.created_at (SQL: insert into "article_tag" ("article_id", "tag_id") values (1, 1))'
这里的 $article->tags()->attach(1),就是通过 tags() 方法将 id=1 的 tag 绑定(attach)到该 article 上。
不幸的是,我们报错了,原因就是没有创建时间。改一下吧。
打开 Article.php ,找到 tags() 方法,修改成如下:
public function tags(){ return $this->belongsToMany('App\Tag')->withTimestamps();}
就是这样。
再执行 attach 命令:
>>> $article = App\Article::first();=> App\Article {#655 id: "1", user_id: "1", created_at: "2016-03-20 15:05:18", updated_at: "2016-03-20 15:05:18", title: "谭晓龙创建的文章", body: "真的是", published_at: "2016-03-28 00:00:00", }>>> $article->tags()->attach(1); => null>>> DB::select('select * from article_tag');=> [ {#650 +"article_id": "1", +"tag_id": "1", +"created_at": "2016-04-30 14:00:31", +"updated_at": "2016-04-30 14:00:31", }, ]>>> $article->tags->toArray();=> [ [ "id" => 1, "name" => "personal", "created_at" => "2016-04-30 13:48:49", "updated_at" => "2016-04-30 13:48:49", "pivot" => [ "article_id" => "1", "tag_id" => "1", "created_at" => "2016-04-30 14:00:31", "updated_at" => "2016-04-30 14:00:31", ], ], ]>>> $article->toArray();=> [ "id" => 1, "user_id" => "1", "created_at" => "2016-03-20 15:05:18", "updated_at" => "2016-03-20 15:05:18", "title" => "谭晓龙创建的文章", "body" => "真的是", "published_at" => "2016-03-28 00:00:00", "tags" => [ [ "id" => 1, "name" => "personal", "created_at" => "2016-04-30 13:48:49", "updated_at" => "2016-04-30 13:48:49", "pivot" => [ "article_id" => "1", "tag_id" => "1", "created_at" => "2016-04-30 14:00:31", "updated_at" => "2016-04-30 14:00:31", ], ], ], ]>>> $article->tags->lists('name'); => Illuminate\Support\Collection {#653 all: [ "personal", ], }
给文章关联完之后,我们再给 tag 关联文章:
>>> $tag=App\Tag::first();=> App\Tag {#666 id: "1", name: "personal", created_at: "2016-04-30 13:48:49", updated_at: "2016-04-30 13:48:49", }>>> $tag->articles->toArray();=> [ [ "id" => 1, "user_id" => "1", "created_at" => "2016-03-20 15:05:18", "updated_at" => "2016-03-20 15:05:18", "title" => "谭晓龙创建的文章", "body" => "真的是", "published_at" => "2016-03-28 00:00:00", "pivot" => [ "tag_id" => "1", "article_id" => "1", ], ], ]
哈哈,tag 以及你个自动被绑定到了 article ,直接现实了出来。
这就是今天要讲的内容,相当于是对 Relationship 的扩展和应用吧。
希望今天的内容你能吸收消化。共勉。