Tự học Laravel: (33) MANY-TO-MANY RELATION MODEL / DB

This time we will add the ability to tag articles. You will learn many-to-many relationships in the implementation of this feature.

I think you are familiar with people who are doing blogs, but the tag specifications are as follows.

  • Multiple tags can be added to articles (n tags for 1 article)
  • Tag can have multiple articles (n articles for 1 tag)
  • Articles belong to multiple tags
  • Tags belong to multiple articles

MODEL

First, create a tag model.

php artisan make:model Tag 

The following files are created:

app/Tag.php 

Implement a many-to-many relationship to the model. 
We used the belongsTo() method in the Article model when we associated the User and Article models on a one-to-many basis, but we use belongsToMany() for many-to-many.

ARTICLE

<?php
// app/Article.php
 
namespace App;
 
...
 
class Article extends Model
{
 
    ...
 
    public function user()
    {
        return $this->belongsTo('App\User');
    }
 
    public function tags()
    {
        return $this->belongsToMany('App\Tag')->withTimestamps();
    }
}

TAG

<?php
// app/Tag.php
 
namespace App;
 
use Illuminate\Database\Eloquent\Model;
 
class Tag extends Model
{
    protected $fillable = ['name'];
 
    public function articles()
    {
        return $this->belongsToMany('App\Article')->withTimestamps();;
    }
}

Pass the associated model name in the first argument of the belongsToMany() method.

The second argument passes a many-to-many intermediate table name. In the above example, the second argument is omitted. If omitted, the intermediate table name will be the alphabetical order of model names. Specify the second argument when you want to specify an intermediate table name that deviates from the standard.

return $ this->belongsToMany('App\Article');
return $ this->belongsToMany('App\Article', 'article_tag');
// The above is the same.

The third and fourth keys specify the foreign key of the intermediate table. If omitted, the model name _id will be the foreign key. Specify the 3rd and 4th keys when you want to specify something out of the rules for the foreign key.

return $this->belongsToMany('App\Article', 'article_tag');
return $ this->belongsToMany('App\Article', 'article_tag', 'article_id', 'tag_id');
// The above is the same.

You also need to use withTimestamps() to update the intermediate table timestamps.

Please see the official site for details.

http://laravel.com/docs/master/eloquent-relationships#many-to-many

MIGRATION

Create a migration that creates the tags and article_tag tables.

php artisan make:migration create_tags_table
php artisan make:migration create_article_tag_table
<?php
// database/migrations/YYYY_MM_DD_XXXXXX_create_tags_table.php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreateTagsTable extends Migration
{
    public function up()
    {
        Schema::create('tags', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->timestamps();
        });
    }
 
    public function down()
    {
        Schema::dropIfExists('tags');
    }
}
<?php
// database/migrations/YYYY_MM_DD_XXXXXX_create_article_tag_table.php
 
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreateArticleTagTable extends Migration
{
    public function up()
    {
        Schema::create('article_tag', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('article_id');
            $table->unsignedInteger('tag_id');
            $table->timestamps();
 
            $table->unique(['article_id', 'tag_id']);
            $table->foreign('article_id')
                ->references('id')
                ->on('articles')
                ->onDelete('cascade');
            $table->foreign('tag_id')
                ->references('id')
                ->on('tags')
                ->onDelete('cascade');
        });
    }
 
    public function down()
    {
        Schema::dropIfExists('article_tag');
    }
}

Along with the tag table, create an intermediate table of articles and tags. The intermediate table sets the table name to the related model name in alphabetical order (article_tag) and sets the foreign key to the article table and tag table. Add the onDelete constraint to delete records in the intermediate table when the related article or tag is deleted.

Perform migration

php artisan migrate

OPERATION CHECK

Let’s check the operation using tinker.

CREATE TAG

$ php artisan tinker

>>> $tag_diary = App\Tag::create(['name' => 'diary'])
>>> $tag_work = App\Tag::create(['name' => 'work'])
>>> $tag_hobby = App\Tag::create(['name' => 'hobby'])
>>> $tag_family = App\Tag::create(['name' => 'family'])
>>> App\Tag::all()->toArray()
=> [
       [
           "id"         => "1",
           "name"       => "diary",
           "created_at" => "2015-03-28 18:11:40",
           "updated_at" => "2015-03-28 18:11:40"
       ],
       [
           "id"         => "2",
           "name"       => "work",
           "created_at" => "2015-03-28 18:11:57",
           "updated_at" => "2015-03-28 18:11:57"
       ],
       [
           "id"         => "3",
           "name"       => "hobby",
           "created_at" => "2015-03-28 18:13:18",
           "updated_at" => "2015-03-28 18:13:18"
       ],
       [
           "id"         => "4",
           "name"       => "family",
           "created_at" => "2015-03-28 18:13:45",
           "updated_at" => "2015-03-28 18:13:45"
       ]
   ]
>>> App\Tag::pluck('name')->toArray();
=> [
       "diary",
       "work",
       "hobby",
       "family"
   ]
>>>

ASSOCIATE TAGS WITH ARTICLES

>>> $article = App\Article::first()
>>> $article->tags()->attach($tag_diary->id)  // ①
>>> 
>>> DB::select('select * from article_tag')
=> [
        {
           article_id: "1",
           tag_id: "1",
           created_at: "2015-03-28 21:07:56",
           updated_at: "2015-03-28 21:07:56"
       }
   ]
>>> 
>>> $article = App\Article::first()
>>> $article->tags->toArray()
=> [
       [
           "id"         => "1",
           "name"       => "diary",
           "created_at" => "2015-03-28 18:11:40",
           "updated_at" => "2015-03-28 18:11:40",
           "pivot"      => [
               "article_id" => "1",
               "tag_id"     => "1",
               "created_at" => "2015-03-28 21:07:56",
               "updated_at" => "2015-03-28 21:07:56"
           ]
       ]
   ]
>>> 

To insert a many-to-many model 1 Use the attach() method.

SEE ARTICLES FROM THE TAG SIDE

Let’s refer to the article from the tag side associated with the above.

>>> $tag = App\Tag::first();
>>> $tag->articles->toArray();
=> [
       [
           "id"           => "1",
           "user_id"      => "3",
           "title"        => "OMNIS ARCHITECTO ODIO REPELLAT ET VOLUPTATEM BEATAE.",
           "body"         => "Minus magni est dignissimos est excepturi incidunt. Eligendi et consequatur sunt adipisci laborum corrupti repudiandae vero. Dolor eum perspiciatis enim non reiciendis.",
           "created_at"   => "2015-03-22 17:24:56",
           "updated_at"   => "2015-03-22 19:28:45",
           "published_at" => "2015-03-22 00:00:00",
           "pivot"        => [
               "tag_id"     => "1",
               "article_id" => "1",
               "created_at" => "2015-03-28 21:07:56",
               "updated_at" => "2015-03-28 21:07:56"
           ]
       ]
   ]
>>> 

The creation of many-to-many relationships worked well. Next time, we will operate many-to-many through the screen.

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.