diff --git a/migrations/Version20250510142748.php b/migrations/Version20250510142748.php new file mode 100644 index 0000000..76c46e1 --- /dev/null +++ b/migrations/Version20250510142748.php @@ -0,0 +1,44 @@ +addSql(<<<'SQL' + ALTER TABLE snip DROP INDEX IDX_FEBD97966A1E45F3, ADD UNIQUE INDEX UNIQ_FEBD97966A1E45F3 (active_version_id) + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE snip ADD archived TINYINT(1) NOT NULL + SQL); + $this->addSql(<<<'SQL' + UPDATE snip SET archived = 0 + SQL); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql(<<<'SQL' + ALTER TABLE snip DROP INDEX UNIQ_FEBD97966A1E45F3, ADD INDEX IDX_FEBD97966A1E45F3 (active_version_id) + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE snip DROP archived + SQL); + } +} diff --git a/src/Controller/SnipController.php b/src/Controller/SnipController.php index 9316153..418229b 100644 --- a/src/Controller/SnipController.php +++ b/src/Controller/SnipController.php @@ -151,4 +151,19 @@ class SnipController extends AbstractController 'form' => $form->createView(), ]); } + + #[Route('/archive/{snip}', name: '_archive')] + public function archive(Snip $snip): Response + { + $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); + $snip->setArchived(!$snip->isArchived()); + $this->repository->save($snip); + if ($snip->isArchived()) { + $this->addFlash('success', sprintf('Snip "%s" archived', $snip)); + } else { + $this->addFlash('success', sprintf('Snip "%s" unarchived', $snip)); + } + + return $this->redirectToRoute('snip_single', ['snip' => $snip->getId()]); + } } \ No newline at end of file diff --git a/src/Dto/SnipFilterRequest.php b/src/Dto/SnipFilterRequest.php index 9326b91..e9b8dae 100644 --- a/src/Dto/SnipFilterRequest.php +++ b/src/Dto/SnipFilterRequest.php @@ -7,6 +7,7 @@ readonly class SnipFilterRequest implements CachableDtoInterface public const string VISIBILITY_ALL = 'all'; public const string VISIBILITY_VISIBLE = 'visible'; public const string VISIBILITY_HIDDEN = 'hidden'; + public const string VISIBILITY_ARCHIVED = 'archived'; public const string SORT_NAME = 'name'; public const string SORT_DATE = 'date'; diff --git a/src/Entity/Snip.php b/src/Entity/Snip.php index ca38fa4..4a559d7 100644 --- a/src/Entity/Snip.php +++ b/src/Entity/Snip.php @@ -36,6 +36,9 @@ class Snip #[ORM\Column] private bool $visible = true; + #[ORM\Column] + private bool $archived = false; + public function __construct() { $this->snipContents = new ArrayCollection(); @@ -145,4 +148,16 @@ class Snip return $this; } + + public function isArchived(): ?bool + { + return $this->archived; + } + + public function setArchived(bool $archived): static + { + $this->archived = $archived; + + return $this; + } } diff --git a/src/Repository/SnipRepository.php b/src/Repository/SnipRepository.php index 71cf64f..0326184 100644 --- a/src/Repository/SnipRepository.php +++ b/src/Repository/SnipRepository.php @@ -50,6 +50,7 @@ class SnipRepository extends ServiceEntityRepository ->setParameter('user', $user) ; + $showArchived = false; switch ($request->visibility) { case SnipFilterRequest::VISIBILITY_ALL: break; @@ -59,9 +60,13 @@ class SnipRepository extends ServiceEntityRepository case SnipFilterRequest::VISIBILITY_HIDDEN: $qb->andWhere('s.visible = false'); break; + case SnipFilterRequest::VISIBILITY_ARCHIVED: + $showArchived = true; + break; default: throw new \InvalidArgumentException('Invalid visibility option: ', $request->visibility); } + $qb->andWhere('s.archived = ' . ($showArchived ? 'true' : 'false')); switch ($request->sort) { case SnipFilterRequest::SORT_NAME: @@ -73,6 +78,7 @@ class SnipRepository extends ServiceEntityRepository default: throw new \InvalidArgumentException('Invalid sort option: ', $request->sort); } + return $qb->getQuery()->getResult(); } @@ -82,6 +88,7 @@ class SnipRepository extends ServiceEntityRepository ->createQueryBuilder('s') ->where('s.public = true') ->andWhere('s.visible = true') + ->andWhere('s.archived = false') ->orderBy('s.createdAt', 'DESC') ; diff --git a/templates/snip/badge.html.twig b/templates/snip/badge.html.twig index 18dcb61..9169691 100644 --- a/templates/snip/badge.html.twig +++ b/templates/snip/badge.html.twig @@ -16,4 +16,10 @@ +{% endif %} + +{% if snip.archived %} + + Archived + {% endif %} \ No newline at end of file diff --git a/templates/snip/index.html.twig b/templates/snip/index.html.twig index 2c275ac..2e1e74c 100644 --- a/templates/snip/index.html.twig +++ b/templates/snip/index.html.twig @@ -33,11 +33,11 @@ {% endfor %} - +
Visibility
- {% for visibilityOption in ['all', 'visible', 'hidden'] %} + {% for visibilityOption in ['all', 'visible', 'hidden', 'archived'] %} Show {{ visibilityOption|capitalize }} diff --git a/templates/snip/single.html.twig b/templates/snip/single.html.twig index 3d92206..3fbd137 100644 --- a/templates/snip/single.html.twig +++ b/templates/snip/single.html.twig @@ -13,17 +13,26 @@ {% endif %} {% if is_granted('edit', snip) %} - - Edit - Versions + + Edit + + {% if snip.archived %} + + Unarchive + + {% else %} + + Archive + + {% endif %} Delete {% endif %} - + Raw

@@ -58,10 +67,10 @@ {{ parent() }} {% endblock %} \ No newline at end of file