From 0648db62e3aa791380d549753ba9f741325f0148 Mon Sep 17 00:00:00 2001 From: Tim Date: Sat, 10 May 2025 21:10:00 +0200 Subject: [PATCH] Add all and none special tags --- src/Dto/SnipFilterRequest.php | 2 +- src/Entity/Tag.php | 3 +++ src/Form/TagsType.php | 26 +++++++++++++++++----- src/Repository/SnipRepository.php | 6 ++++- src/Twig/Extension/SnipFilterExtension.php | 3 ++- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/Dto/SnipFilterRequest.php b/src/Dto/SnipFilterRequest.php index 6e73503..8959325 100644 --- a/src/Dto/SnipFilterRequest.php +++ b/src/Dto/SnipFilterRequest.php @@ -15,7 +15,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface public function __construct( public ?string $visibility = self::VISIBILITY_VISIBLE, public ?string $sort = self::SORT_DATE, - public ?string $tag = null, + public ?string $tag = 'all', ) {} public function toArray(): array diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index 5a430e3..de600ff 100644 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -6,6 +6,7 @@ use App\Repository\TagRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity(repositoryClass: TagRepository::class)] #[ORM\UniqueConstraint(name: 'user_tag_unique', columns: ['name', 'user_id'])] @@ -17,6 +18,8 @@ class Tag private ?int $id = null; #[ORM\Column(length: 255)] + #[Assert\NotEqualTo('all')] + #[Assert\NotEqualTo('none')] private ?string $name = null; #[ORM\ManyToOne] diff --git a/src/Form/TagsType.php b/src/Form/TagsType.php index d5135d2..72942d8 100644 --- a/src/Form/TagsType.php +++ b/src/Form/TagsType.php @@ -8,15 +8,19 @@ use Doctrine\Common\Collections\Collection; use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\ConstraintViolationInterface; +use Symfony\Component\Validator\Validator\ValidatorInterface; class TagsType extends AbstractType implements DataTransformerInterface { public function __construct( - private readonly TagRepository $repository, - private readonly Security $security, + private readonly TagRepository $repository, + private readonly Security $security, + private readonly ValidatorInterface $validator, ) {} public function transform($value): string @@ -46,10 +50,20 @@ class TagsType extends AbstractType implements DataTransformerInterface foreach ($tags as $tag) { $tagEntity = $this->repository->findOneBy(['name' => $tag, 'user' => $user]); if ($tagEntity === null) { - $tagEntity = new Tag() - ->setName($tag) - ->setUser($user) - ; + $tagEntity = new Tag(); + $tagEntity->setName($tag)->setUser($user); + + // Validate the new Tag entity + $errors = $this->validator->validate($tagEntity); + if (count($errors) > 0) { + $exception = new TransformationFailedException(); + $exception->setInvalidMessage(implode(', ', array_map( + fn(ConstraintViolationInterface $error) => $error->getMessage(), + iterator_to_array($errors) + ))); + throw $exception; + } + $this->repository->save($tagEntity); } $tagEntities[] = $tagEntity; diff --git a/src/Repository/SnipRepository.php b/src/Repository/SnipRepository.php index 72c23d9..c60ed4d 100644 --- a/src/Repository/SnipRepository.php +++ b/src/Repository/SnipRepository.php @@ -79,7 +79,11 @@ class SnipRepository extends ServiceEntityRepository throw new \InvalidArgumentException('Invalid sort option: ', $request->sort); } - if ($request->tag) { + if ($request->tag === 'none') { + $qb->andWhere('s.tags IS EMPTY'); + } elseif ($request->tag === 'all') { + // No filter needed + } else { $qb->innerJoin('s.tags', 't') ->andWhere('t.name = :tag') ->setParameter('tag', $request->tag) diff --git a/src/Twig/Extension/SnipFilterExtension.php b/src/Twig/Extension/SnipFilterExtension.php index 04d1020..0743b49 100644 --- a/src/Twig/Extension/SnipFilterExtension.php +++ b/src/Twig/Extension/SnipFilterExtension.php @@ -25,7 +25,8 @@ class SnipFilterExtension extends AbstractExtension private function getSnipTagOptions(): array { - $tags[null] = 'All tags'; + $tags['all'] = 'All tags'; + $tags['none'] = 'No tags'; foreach ($this->tagRepository->findAllByUser($this->security->getUser()) as $tag) { $tags[(string)$tag] = (string)$tag; }