Change snip and tag entities to public columns

This commit is contained in:
Tim
2025-07-24 14:51:55 +02:00
parent 8226ac24d8
commit 074c1d8570
15 changed files with 70 additions and 225 deletions

View File

@ -34,11 +34,11 @@ class ApiController extends AbstractApiController
$this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip); $this->denyAccessUnlessGranted(SnipVoter::VIEW, $snip);
return $this->successResponse([ return $this->successResponse([
'id' => $snip->getId(), 'id' => $snip->id,
'content' => $snip->getActiveText(), 'content' => $snip->getActiveText(),
'createdBy' => [ 'createdBy' => [
'id' => $snip->getCreatedBy()->getId(), 'id' => $snip->createdBy->getId(),
'name' => $snip->getCreatedBy()->getName(), 'name' => $snip->createdBy->getName(),
], ],
]); ]);
} }
@ -53,7 +53,7 @@ class ApiController extends AbstractApiController
{ {
$this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip);
if (!($snip->getActiveVersion() === $snip->getLatestVersion())) { if (!($snip->activeVersion === $snip->getLatestVersion())) {
return $this->errorResponse('Snip is not the latest version'); return $this->errorResponse('Snip is not the latest version');
} }
@ -64,12 +64,12 @@ class ApiController extends AbstractApiController
} }
return $this->successResponse([ return $this->successResponse([
'id' => $snip->getId(), 'id' => $snip->id,
'name' => $snip->getName(), 'name' => $snip->name,
'content' => $snip->getActiveText(), 'content' => $snip->getActiveText(),
'createdBy' => [ 'createdBy' => [
'id' => $snip->getCreatedBy()->getId(), 'id' => $snip->createdBy->getId(),
'name' => $snip->getCreatedBy()->getName(), 'name' => $snip->createdBy->getName(),
], ],
]); ]);
} }

View File

@ -85,21 +85,20 @@ class SnipController extends AbstractController
* Temporary solution to prevent editing of old versions * Temporary solution to prevent editing of old versions
* It technically fully works, but rendering the version history needs an update first * It technically fully works, but rendering the version history needs an update first
*/ */
$isLatest = $snip->getActiveVersion() === $snip->getLatestVersion(); $isLatest = $snip->activeVersion === $snip->getLatestVersion();
if (!$isLatest) { if (!$isLatest) {
$this->addFlash('error', 'Snip is not the latest version, changes will not be saved.'); $this->addFlash('error', 'Snip is not the latest version, changes will not be saved.');
} }
$form = $this->createForm(SnipType::class, $snip) $form = $this->createForm(SnipType::class, $snip)
->add('Save', SubmitType::class) ->add('Save', SubmitType::class);
;
$form->get('content')->setData($snip->getActiveText()); $form->get('content')->setData($snip->getActiveText());
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
if (!$isLatest) { if (!$isLatest) {
return $this->redirectToRoute('snip_single', [ return $this->redirectToRoute('snip_single', [
'snip' => $snip->getId(), 'snip' => $snip->id,
]); ]);
} }
$this->repository->save($snip); $this->repository->save($snip);
@ -112,7 +111,7 @@ class SnipController extends AbstractController
$this->addFlash('success', sprintf('Snip "%s" saved', $snip)); $this->addFlash('success', sprintf('Snip "%s" saved', $snip));
return $this->redirectToRoute('snip_single', [ return $this->redirectToRoute('snip_single', [
'snip' => $snip->getId(), 'snip' => $snip->id,
]); ]);
} }
@ -126,9 +125,8 @@ class SnipController extends AbstractController
public function new(Request $request, SnipContentService $contentService): Response public function new(Request $request, SnipContentService $contentService): Response
{ {
$snip = new Snip(); $snip = new Snip();
$snip->setCreatedAtNow() $snip->setCreatedAtNow();
->setCreatedBy($this->getUser()) $snip->createdBy = $this->getUser();
;
$form = $this->createForm(SnipType::class, $snip); $form = $this->createForm(SnipType::class, $snip);
$form->add('Create', SubmitType::class); $form->add('Create', SubmitType::class);
@ -145,7 +143,7 @@ class SnipController extends AbstractController
$this->addFlash('success', sprintf('Snip "%s" created', $snip)); $this->addFlash('success', sprintf('Snip "%s" created', $snip));
return $this->redirectToRoute('snip_single', [ return $this->redirectToRoute('snip_single', [
'snip' => $snip->getId(), 'snip' => $snip->id,
]); ]);
} }
@ -163,7 +161,7 @@ class SnipController extends AbstractController
$form = $this->createForm(ConfirmationType::class); $form = $this->createForm(ConfirmationType::class);
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$snip->setActiveVersion(null); $snip->activeVersion = null;
$this->repository->save($snip); $this->repository->save($snip);
$this->repository->remove($snip); $this->repository->remove($snip);
$this->addFlash('success', sprintf('Snip "%s" deleted', $snip)); $this->addFlash('success', sprintf('Snip "%s" deleted', $snip));
@ -180,14 +178,14 @@ class SnipController extends AbstractController
public function archive(Snip $snip): Response public function archive(Snip $snip): Response
{ {
$this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip); $this->denyAccessUnlessGranted(SnipVoter::EDIT, $snip);
$snip->setArchived(!$snip->isArchived()); $snip->archived = !$snip->archived;
$this->repository->save($snip); $this->repository->save($snip);
if ($snip->isArchived()) { if ($snip->archived) {
$this->addFlash('success', sprintf('Snip "%s" archived', $snip)); $this->addFlash('success', sprintf('Snip "%s" archived', $snip));
} else { } else {
$this->addFlash('success', sprintf('Snip "%s" unarchived', $snip)); $this->addFlash('success', sprintf('Snip "%s" unarchived', $snip));
} }
return $this->redirectToRoute('snip_edit', ['snip' => $snip->getId()]); return $this->redirectToRoute('snip_edit', ['snip' => $snip->id]);
} }
} }

View File

@ -34,6 +34,6 @@ class VersionController extends AbstractController
$this->contentService->setVersion($snip, $version); $this->contentService->setVersion($snip, $version);
$this->addFlash('success', 'Snip version set to ' . $version->getId()); $this->addFlash('success', 'Snip version set to ' . $version->getId());
return $this->redirectToRoute('snip_single', ['snip' => $snip->getId()]); return $this->redirectToRoute('snip_single', ['snip' => $snip->id]);
} }
} }

View File

@ -17,13 +17,13 @@ class SnipPostRequest
public function pushToSnip(Snip $snip): void public function pushToSnip(Snip $snip): void
{ {
if ($this->name !== null) { if ($this->name !== null) {
$snip->setName($this->name); $snip->name = $this->name;
} }
if ($this->public !== null) { if ($this->public !== null) {
$snip->setPublic($this->public); $snip->public = $this->public;
} }
if ($this->visible !== null) { if ($this->visible !== null) {
$snip->setVisible($this->visible); $snip->visible = $this->visible;
} }
} }
} }

View File

@ -10,46 +10,22 @@ trait TrackedTrait
{ {
#[ORM\Column] #[ORM\Column]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private ?DateTime $createdAt = null; public ?DateTime $createdAt = null;
#[ORM\ManyToOne] #[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private ?User $createdBy = null; public ?User $createdBy = null;
public function getCreatedBy(): ?User
{
return $this->createdBy;
}
public function setCreatedBy(?User $createdBy): self
{
$this->createdBy = $createdBy;
return $this;
}
public function getCreatedAt(): ?DateTime
{
return $this->createdAt;
}
public function setCreatedAt(DateTime $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function setCreatedAtNowNoSeconds(): self public function setCreatedAtNowNoSeconds(): self
{ {
$this->setCreatedAt(DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d H:i'))); $this->createdAt = DateTime::createFromFormat('Y-m-d H:i', date('Y-m-d H:i'));
return $this; return $this;
} }
public function setCreatedAtNow(): self public function setCreatedAtNow(): self
{ {
$this->setCreatedAt(new DateTime()); $this->createdAt = new DateTime();
return $this; return $this;
} }

View File

@ -17,34 +17,34 @@ class Snip
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
private ?int $id = null; public ?int $id = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private ?string $name = null; public ?string $name = null;
#[ORM\Column] #[ORM\Column]
private bool $public = false; public bool $public = false;
#[ORM\OneToMany(mappedBy: 'snip', targetEntity: SnipContent::class, orphanRemoval: true)] #[ORM\OneToMany(mappedBy: 'snip', targetEntity: SnipContent::class, orphanRemoval: true)]
private Collection $snipContents; public Collection $snipContents;
#[ORM\OneToOne] #[ORM\OneToOne]
private ?SnipContent $activeVersion = null; public ?SnipContent $activeVersion = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private ?string $parser = null; public ?string $parser = null;
#[ORM\Column] #[ORM\Column]
private bool $visible = true; public bool $visible = true;
#[ORM\Column] #[ORM\Column]
private bool $archived = false; public bool $archived = false;
/** /**
* @var Collection<int, Tag> * @var Collection<int, Tag>
*/ */
#[ORM\ManyToMany(targetEntity: Tag::class, mappedBy: 'snips')] #[ORM\ManyToMany(targetEntity: Tag::class, mappedBy: 'snips')]
private Collection $tags; public Collection $tags;
public function __construct() public function __construct()
{ {
@ -59,44 +59,7 @@ class Snip
public function getActiveText(): string public function getActiveText(): string
{ {
return SnipContentService::rebuildText($this->getActiveVersion()); return SnipContentService::rebuildText($this->activeVersion);
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function isPublic(): ?bool
{
return $this->public;
}
public function setPublic(bool $public): self
{
$this->public = $public;
return $this;
}
/**
* @return Collection<int, SnipContent>
*/
public function getSnipContents(): Collection
{
return $this->snipContents;
} }
public function addSnipContent(SnipContent $snipContent): self public function addSnipContent(SnipContent $snipContent): self
@ -126,62 +89,6 @@ class Snip
return $this->snipContents->last() ?: null; return $this->snipContents->last() ?: null;
} }
public function getActiveVersion(): ?SnipContent
{
return $this->activeVersion;
}
public function setActiveVersion(?SnipContent $activeVersion): static
{
$this->activeVersion = $activeVersion;
return $this;
}
public function getParser(): ?string
{
return $this->parser;
}
public function setParser(string $parser): static
{
$this->parser = $parser;
return $this;
}
public function isVisible(): ?bool
{
return $this->visible;
}
public function setVisible(bool $visible): static
{
$this->visible = $visible;
return $this;
}
public function isArchived(): ?bool
{
return $this->archived;
}
public function setArchived(bool $archived): static
{
$this->archived = $archived;
return $this;
}
/**
* @return Collection<int, Tag>
*/
public function getTags(): Collection
{
return $this->tags;
}
public function addTag(Tag $tag): static public function addTag(Tag $tag): static
{ {
if (!$this->tags->contains($tag)) { if (!$this->tags->contains($tag)) {

View File

@ -16,22 +16,22 @@ class Tag
#[ORM\Id] #[ORM\Id]
#[ORM\GeneratedValue] #[ORM\GeneratedValue]
#[ORM\Column] #[ORM\Column]
private ?int $id = null; public ?int $id = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
#[Assert\NotEqualTo(SnipFilterRequest::TAG_ALL)] #[Assert\NotEqualTo(SnipFilterRequest::TAG_ALL)]
#[Assert\NotEqualTo(SnipFilterRequest::TAG_NONE)] #[Assert\NotEqualTo(SnipFilterRequest::TAG_NONE)]
private ?string $name = null; public ?string $name = null;
#[ORM\ManyToOne] #[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
private ?User $user = null; public ?User $user = null;
/** /**
* @var Collection<int, Snip> * @var Collection<int, Snip>
*/ */
#[ORM\ManyToMany(targetEntity: Snip::class, inversedBy: 'tags')] #[ORM\ManyToMany(targetEntity: Snip::class, inversedBy: 'tags')]
private Collection $snips; public Collection $snips;
public function __construct() public function __construct()
{ {
@ -43,43 +43,6 @@ class Tag
return $this->name ?? ''; return $this->name ?? '';
} }
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): static
{
$this->user = $user;
return $this;
}
/**
* @return Collection<int, Snip>
*/
public function getSnips(): Collection
{
return $this->snips;
}
public function addSnip(Snip $snip): static public function addSnip(Snip $snip): static
{ {
if (!$this->snips->contains($snip)) { if (!$this->snips->contains($snip)) {

View File

@ -34,7 +34,7 @@ class TagsType extends AbstractType implements DataTransformerInterface
} }
if (is_array($value)) { if (is_array($value)) {
$tags = array_map(fn(Tag $tag) => $tag->getName(), $value); $tags = array_map(fn(Tag $tag) => $tag->name, $value);
} else { } else {
return ''; return '';
} }
@ -51,7 +51,8 @@ class TagsType extends AbstractType implements DataTransformerInterface
$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();
$tagEntity->setName($tag)->setUser($user); $tagEntity->name = $tag;
$tagEntity->user = $user;
// Validate the new Tag entity // Validate the new Tag entity
$errors = $this->validator->validate($tagEntity); $errors = $this->validator->validate($tagEntity);

View File

@ -29,14 +29,14 @@ class SnipVoter extends Voter
switch ($attribute) { switch ($attribute) {
case self::VIEW: case self::VIEW:
if ($subject->isPublic()) { if ($subject->public) {
return true; return true;
} }
case self::EDIT: case self::EDIT:
if (!$user instanceof UserInterface) { if (!$user instanceof UserInterface) {
return false; return false;
} }
if ($subject->getCreatedBy() === $user) { if ($subject->createdBy === $user) {
return true; return true;
} }
break; break;

View File

@ -15,7 +15,7 @@ readonly class SnipContentService
public function update(Snip $snip, string $contents, ?string $contentName): void public function update(Snip $snip, string $contents, ?string $contentName): void
{ {
$parentContent = $snip->getActiveVersion(); $parentContent = $snip->activeVersion;
if (self::rebuildText($parentContent) === $contents) { if (self::rebuildText($parentContent) === $contents) {
return; return;
} }
@ -35,7 +35,7 @@ readonly class SnipContentService
$this->em->persist($content); $this->em->persist($content);
$this->em->flush(); $this->em->flush();
$snip->setActiveVersion($content); $snip->activeVersion = $content;
$this->em->persist($snip); $this->em->persist($snip);
$this->em->flush(); $this->em->flush();
} }
@ -61,11 +61,11 @@ readonly class SnipContentService
public function setVersion(Snip $snip, SnipContent $version): void public function setVersion(Snip $snip, SnipContent $version): void
{ {
$activeVersion = $snip->getActiveVersion(); $activeVersion = $snip->activeVersion;
$this->contentToAbsolute($version); $this->contentToAbsolute($version);
$this->contentToRelative($activeVersion); $this->contentToRelative($activeVersion);
$snip->setActiveVersion($version); $snip->activeVersion = $version;
$this->em->persist($snip); $this->em->persist($snip);
$this->em->flush(); $this->em->flush();
} }

View File

@ -41,7 +41,7 @@ class IncludeReferenceStage implements StageInterface
} else { } else {
$snip = $this->snipRepository->find($id); $snip = $this->snipRepository->find($id);
if ($snip) { if ($snip) {
$content = $this->snipContentRepository->find($snip->getActiveVersion()); $content = $this->snipContentRepository->find($snip->activeVersion);
} }
} }
if ($content === null) { if ($content === null) {

View File

@ -36,7 +36,7 @@ readonly class UrlReferenceStage implements StageInterface
return sprintf('<span title="access denied">%s</span>', $matches[0]); return sprintf('<span title="access denied">%s</span>', $matches[0]);
} }
$url = $this->router->generate('snip_single', ['snip' => $snip->getId()]); $url = $this->router->generate('snip_single', ['snip' => $snip->id]);
return sprintf('<a href="%s">%s</a>', $url, $snip); return sprintf('<a href="%s">%s</a>', $url, $snip);
}, $payload); }, $payload);
} }

View File

@ -29,9 +29,9 @@ readonly class ParserFactory
public function getBySnip(Snip $snip): ParserInterface public function getBySnip(Snip $snip): ParserInterface
{ {
$parser = $snip->getParser(); $parser = $snip->parser;
if (null === $parser) { if (null === $parser) {
throw new ServiceNotFoundException(sprintf('Unknown parser for snip "%s"', $snip->getParser())); throw new ServiceNotFoundException(sprintf('Unknown parser for snip "%s"', $snip->parser));
} }
return $this->get($parser); return $this->get($parser);

View File

@ -25,7 +25,7 @@ class SnipLoader implements LoaderInterface
public function getCacheKey(string $name): string public function getCacheKey(string $name): string
{ {
return $this->getFromKey($name)->getActiveVersion()->getId(); return $this->getFromKey($name)->activeVersion->getId();
} }
public function isFresh(string $name, int $time): bool public function isFresh(string $name, int $time): bool

View File

@ -56,8 +56,8 @@ class SnipTwigExtension extends AbstractExtension
$request = new SnipFilterRequest(SnipFilterRequest::VISIBILITY_ALL, tag: $tag); $request = new SnipFilterRequest(SnipFilterRequest::VISIBILITY_ALL, tag: $tag);
$snips = $this->snipRepo->findByRequest($user, $request); $snips = $this->snipRepo->findByRequest($user, $request);
return array_map(fn(Snip $snip) => [ return array_map(fn(Snip $snip) => [
'id' => $snip->getId(), 'id' => $snip->id,
'name' => $snip->getName(), 'name' => $snip->name,
], $snips); ], $snips);
} }
} }