Laravel Eloquent Relationships: Many To Many

Eloquent Relationships Laravel Eloquent Relationships: Many To Many

Many To Many Relationships

We will look at the article and the tags that are attached to the article as an example.

Tables Structure

To define this type of relationship, we need three database tables: articles, tags, and intermediate table article_tag. The article_tag table's name must contain the names of the models in alphabetical order and has id models columns.

articles // Articles Table 
    id - integer
    name - string
 
tags // Tags Table
    id - integer
    name - string
 
article_tag // Pivot Table
    article_id - integer
    tag_id - integer

Model Structure

Now we will define a method through which we can get all the tags for the article using the intermediate table.

<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
class Article extends Model
{
    /**
     * The tags that belong to the article.
     */
    public function tags() : BelongsToMany
    {
        return $this->belongsToMany(Tag::class);
    }
}

We can also get all articles that contain a certain tag. Let's add a method to the tag model.

public function articles() : BelongsToMany
{
	return $this->belongsToMany(Article::class);
}

Customizing the name of the intermediate table

In addition to naming the intermediate table, you can customize the column names of the keys that connect the two tables by providing extra arguments to the belongsToMany method.

public function tags() : BelongsToMany
{
    return $this->belongsToMany(Tag::class, 'article_tag_custom');
}

Access to model dynamic relationship property

You may access the article tags using the roles dynamic relationship property

$article = Article::find($id);
 
foreach ($article->tags as $tag) {
    //
}

$tag = Tag::find($id);
 
foreach ($tag->articles as $article) {
    //
}

Access to model method

$tags = Article::find($id)->tags()->orderBy('name')->get();

$articles = Tag::find($id)->articles()->orderBy('updated_at', 'desc')->paginate(10);

Attaching relationships

You may create a tag model and then use the attach method for creating rows in the intermediate table.

/**
 * Tag Attach
 *
 * @param Article $article
 * @param StoreRequest $request
 *
 * @return void
 */
public function attach(Article $article, StoreRequest $request) : void
{
	$tag = Tag::create($request->validated());

	$article->tags()->attach($tag->id);
}

Detaching relationships

To remove the relationship between tag and article, use the detach method.

// Detach a single tag from the article
$article->tags()->detach($tag->id);
 
// Detach all tags from the article
$article->tags()->detach();

Syncing Associations

Also, you can use the sync method to remove all relationships between tags and certain article, then add new relationships from the array.

$tagIds = [1, 2, 3];

$article->tags()->sync($tagIds);

You can use the syncWithoutDetaching method if you don't want to detach existing IDs that are missing from the specified array.

$article->tags()->syncWithoutDetaching([$tag->id]);

$tagIds = [1, 2, 3];

$article->tags()->syncWithoutDetaching($tagIds);