phplaravelmany-to-manylaravel-8

How can I use a many-to-many relationship to display articles by tag in Laravel?


I am working on a blogging application in Laravel 8.

I am trying to display articles by tag at the following route:

Route::get('/tag/{tag_id}', [ArticlesController::class, 'tag'])->name('tag');

In the ArticlesController controller, I have the tag() method, which is supposed to display all posts that contain a certain tag:

public function tag($tag_id)
{
    $tag   = Tag::firstWhere('id', $tag_id);
    $articles = Article::where('id', $tag->id)->orderBy('id', 'desc')->paginate($this->per_page);

    return view(
      'themes/' . $this->theme_directory . '/templates/index',
      array_merge($this->data, [
        'tag'   => $tag,
        'articles' => $articles
      ])
    );
}

There is a many-to-many relationship between articles and tags. I have an article_tag pivot table:

enter image description here

In the Tag model I have:

class Tag extends Model
{
   use HasFactory;

   protected $fillable = ['name'];

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

To the Article model I have added the tags() method

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

The problem

The /tag/1 displays only one article and that article does not contain a tag with the id of 1.

Questions:

  1. Where is my mistake?
  2. What working solution requires minimal change in the current code?

Solution

  • It seems that the problem is that you take the article using the tag id, and do not check whether this tag is attached to the article where('id', $tag->id)

    Try using whereHas in the articles query:

    $articles = Article::whereHas('tags', function (Builder $query) use ($tag) {
      $query->where('id', $tag->id);
    })->orderBy('id', 'desc')->paginate($this->per_page);
    

    https://laravel.com/docs/8.x/eloquent-relationships