Add all and none special tags

This commit is contained in:
Tim 2025-05-10 21:10:00 +02:00
parent b8ae8bb8a7
commit 0648db62e3
5 changed files with 31 additions and 9 deletions

View File

@ -15,7 +15,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface
public function __construct( public function __construct(
public ?string $visibility = self::VISIBILITY_VISIBLE, public ?string $visibility = self::VISIBILITY_VISIBLE,
public ?string $sort = self::SORT_DATE, public ?string $sort = self::SORT_DATE,
public ?string $tag = null, public ?string $tag = 'all',
) {} ) {}
public function toArray(): array public function toArray(): array

View File

@ -6,6 +6,7 @@ use App\Repository\TagRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: TagRepository::class)] #[ORM\Entity(repositoryClass: TagRepository::class)]
#[ORM\UniqueConstraint(name: 'user_tag_unique', columns: ['name', 'user_id'])] #[ORM\UniqueConstraint(name: 'user_tag_unique', columns: ['name', 'user_id'])]
@ -17,6 +18,8 @@ class Tag
private ?int $id = null; private ?int $id = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
#[Assert\NotEqualTo('all')]
#[Assert\NotEqualTo('none')]
private ?string $name = null; private ?string $name = null;
#[ORM\ManyToOne] #[ORM\ManyToOne]

View File

@ -8,15 +8,19 @@ use Doctrine\Common\Collections\Collection;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class TagsType extends AbstractType implements DataTransformerInterface class TagsType extends AbstractType implements DataTransformerInterface
{ {
public function __construct( public function __construct(
private readonly TagRepository $repository, private readonly TagRepository $repository,
private readonly Security $security, private readonly Security $security,
private readonly ValidatorInterface $validator,
) {} ) {}
public function transform($value): string public function transform($value): string
@ -46,10 +50,20 @@ class TagsType extends AbstractType implements DataTransformerInterface
foreach ($tags as $tag) { foreach ($tags as $tag) {
$tagEntity = $this->repository->findOneBy(['name' => $tag, 'user' => $user]); $tagEntity = $this->repository->findOneBy(['name' => $tag, 'user' => $user]);
if ($tagEntity === null) { if ($tagEntity === null) {
$tagEntity = new Tag() $tagEntity = new Tag();
->setName($tag) $tagEntity->setName($tag)->setUser($user);
->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); $this->repository->save($tagEntity);
} }
$tagEntities[] = $tagEntity; $tagEntities[] = $tagEntity;

View File

@ -79,7 +79,11 @@ class SnipRepository extends ServiceEntityRepository
throw new \InvalidArgumentException('Invalid sort option: ', $request->sort); 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') $qb->innerJoin('s.tags', 't')
->andWhere('t.name = :tag') ->andWhere('t.name = :tag')
->setParameter('tag', $request->tag) ->setParameter('tag', $request->tag)

View File

@ -25,7 +25,8 @@ class SnipFilterExtension extends AbstractExtension
private function getSnipTagOptions(): array 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) { foreach ($this->tagRepository->findAllByUser($this->security->getUser()) as $tag) {
$tags[(string)$tag] = (string)$tag; $tags[(string)$tag] = (string)$tag;
} }