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:
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:
- Where is my mistake?
- What working solution requires minimal change in the current code?
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:
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:
- Where is my mistake?
- What working solution requires minimal change in the current code?
2 Answers
Reset to default 4It 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
Where is my mistake?
Your issue is with this this line -->
$articles = Article::where('id', $tag->id)->orderBy('id', 'desc')->paginate($this->per_page);
Here you are retrieving the articles where article id is same as tag id.
Solution:
Use the many-to-many relationship that you have defined on the Tag
model. You can retrieve the articles using the relationship like this like this: $tag->article
.
So your full code for the tag method in the ArticleController:
public function tag($tag_id)
{
$tag = Tag::firstWhere('id', $tag_id);
$articles = $tag->article->orderBy('id', 'desc')->paginate($this->per_page);
return view(
'themes/' . $this->theme_directory . '/templates/index',
array_merge($this->data, [
'tag' => $tag,
'articles' => $articles
])
);
}