feat: add tag filtering to blog posts and implement JSON_CONTAINS DQL function

This commit is contained in:
hamed
2026-06-21 17:34:07 +03:30
parent 91cfb64217
commit 21b6c583c0
5 changed files with 69 additions and 10 deletions
+3 -2
View File
@@ -60,9 +60,10 @@ class BlogController extends BaseController
{
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(50, max(1, (int) $request->query->get('limit', 20)));
$tag = $request->query->get('tag') ?: null;
$blogs = array_map(fn(Blog $b) => $b->toListArray(), $this->blogRepo->findPublished($page, $limit));
$total = $this->blogRepo->countPublished();
$blogs = array_map(fn(Blog $b) => $b->toListArray(), $this->blogRepo->findPublished($page, $limit, $tag));
$total = $this->blogRepo->countPublished($tag);
return $this->paginated($blogs, $total, $page, $limit);
}
+24 -8
View File
@@ -14,24 +14,40 @@ class BlogRepository extends ServiceEntityRepository
public function findBySlug(string $slug): ?Blog { return $this->findOneBy(['slug' => $slug]); }
/** @return Blog[] published, newest first */
public function findPublished(int $page = 1, int $limit = 20): array
public function findPublished(int $page = 1, int $limit = 20, ?string $tag = null): array
{
return $this->createQueryBuilder('b')
$qb = $this->createQueryBuilder('b')
->where('b.status = :status')
->setParameter('status', Blog::STATUS_PUBLISHED)
->orderBy('b.createdAt', 'DESC')
->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit)
->getQuery()->getResult();
->setMaxResults($limit);
$this->applyTagFilter($qb, $tag);
return $qb->getQuery()->getResult();
}
public function countPublished(): int
public function countPublished(?string $tag = null): int
{
return (int) $this->createQueryBuilder('b')
$qb = $this->createQueryBuilder('b')
->select('COUNT(b.id)')
->where('b.status = :status')
->setParameter('status', Blog::STATUS_PUBLISHED)
->getQuery()->getSingleScalarResult();
->setParameter('status', Blog::STATUS_PUBLISHED);
$this->applyTagFilter($qb, $tag);
return (int) $qb->getQuery()->getSingleScalarResult();
}
private function applyTagFilter(\Doctrine\ORM\QueryBuilder $qb, ?string $tag): void
{
if ($tag === null || $tag === '') {
return;
}
// Blog.tags is a JSON array of tag names; match exact name membership.
$qb->andWhere('JSON_CONTAINS(b.tags, :tag) = 1')
->setParameter('tag', json_encode($tag, JSON_UNESCAPED_UNICODE));
}
public function save(Blog $e, bool $flush = true): void { $this->getEntityManager()->persist($e); if ($flush) $this->getEntityManager()->flush(); }