add tagging
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
@@ -14,7 +15,7 @@ class Document
|
||||
public const STATUS_ARCHIVED = 'ARCHIVED';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'uuid', unique: true)]
|
||||
#[ORM\Column(type: 'uuid')]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
@@ -28,35 +29,49 @@ class Document
|
||||
private User $createdBy;
|
||||
|
||||
#[ORM\Column]
|
||||
private \DateTimeImmutable $createdAt;
|
||||
private DateTimeImmutable $createdAt;
|
||||
|
||||
// 🔥 REMOVE ergänzt
|
||||
#[ORM\OneToMany(
|
||||
mappedBy: 'document',
|
||||
targetEntity: DocumentVersion::class,
|
||||
cascade: ['persist', 'remove'],
|
||||
mappedBy: 'document',
|
||||
cascade: ['persist'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
private Collection $versions;
|
||||
|
||||
// 🔥 onDelete ergänzt
|
||||
#[ORM\ManyToOne]
|
||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||
private ?DocumentVersion $currentVersion = null;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Tags via Join-Entity (DocumentTag)
|
||||
// ---------------------------------------------------------
|
||||
|
||||
#[ORM\OneToMany(
|
||||
targetEntity: DocumentTag::class,
|
||||
mappedBy: 'document',
|
||||
cascade: ['persist', 'remove'],
|
||||
orphanRemoval: true
|
||||
)]
|
||||
private Collection $documentTags;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->id = Uuid::v4();
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
$this->createdAt = new DateTimeImmutable();
|
||||
$this->versions = new ArrayCollection();
|
||||
$this->documentTags = new ArrayCollection();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// Basic Getters
|
||||
// ---------------------------------------------------------
|
||||
|
||||
public function getId(): Uuid
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeImmutable
|
||||
public function getCreatedAt(): DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
@@ -87,12 +102,14 @@ class Document
|
||||
return $this->createdBy;
|
||||
}
|
||||
|
||||
public function setCreatedBy(User $user): static
|
||||
public function setCreatedBy(User $createdBy): void
|
||||
{
|
||||
$this->createdBy = $user;
|
||||
return $this;
|
||||
$this->createdBy = $createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, DocumentVersion>
|
||||
*/
|
||||
public function getVersions(): Collection
|
||||
{
|
||||
return $this->versions;
|
||||
@@ -106,13 +123,67 @@ class Document
|
||||
}
|
||||
}
|
||||
|
||||
public function getCurrentVersion(): ?DocumentVersion
|
||||
{
|
||||
return $this->currentVersion;
|
||||
}
|
||||
|
||||
public function setCurrentVersion(?DocumentVersion $version): void
|
||||
{
|
||||
$this->currentVersion = $version;
|
||||
}
|
||||
|
||||
public function getCurrentVersion(): ?DocumentVersion
|
||||
// ---------------------------------------------------------
|
||||
// Tag API (Join-Entity basiert)
|
||||
// ---------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @return Collection<int, DocumentTag>
|
||||
*/
|
||||
public function getDocumentTags(): Collection
|
||||
{
|
||||
return $this->currentVersion;
|
||||
return $this->documentTags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience: liefert direkt Tag-Objekte
|
||||
*
|
||||
* @return Tag[]
|
||||
*/
|
||||
public function getTags(): array
|
||||
{
|
||||
return array_map(
|
||||
fn (DocumentTag $dt) => $dt->getTag(),
|
||||
$this->documentTags->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
public function hasTag(Tag $tag): bool
|
||||
{
|
||||
foreach ($this->documentTags as $dt) {
|
||||
if ($dt->getTag()->getId()->equals($tag->getId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function addTag(Tag $tag): void
|
||||
{
|
||||
if ($this->hasTag($tag)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->documentTags->add(new DocumentTag($this, $tag));
|
||||
}
|
||||
|
||||
public function removeTag(Tag $tag): void
|
||||
{
|
||||
foreach ($this->documentTags as $dt) {
|
||||
if ($dt->getTag()->getId()->equals($tag->getId())) {
|
||||
$this->documentTags->removeElement($dt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src/Entity/DocumentTag.php
Normal file
38
src/Entity/DocumentTag.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'document_tag')]
|
||||
class DocumentTag
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\ManyToOne(targetEntity: Document::class, inversedBy: 'documentTags')]
|
||||
#[ORM\JoinColumn(name: 'document_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
||||
private Document $document;
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\ManyToOne(targetEntity: Tag::class)]
|
||||
#[ORM\JoinColumn(name: 'tag_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
||||
private Tag $tag;
|
||||
|
||||
public function __construct(Document $document, Tag $tag)
|
||||
{
|
||||
$this->document = $document;
|
||||
$this->tag = $tag;
|
||||
}
|
||||
|
||||
public function getDocument(): Document
|
||||
{
|
||||
return $this->document;
|
||||
}
|
||||
|
||||
public function getTag(): Tag
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
}
|
||||
82
src/Entity/Tag.php
Normal file
82
src/Entity/Tag.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'knowledge_tag')]
|
||||
#[ORM\Index(name: 'idx_knowledge_tag_slug', columns: ['slug'])]
|
||||
#[ORM\Index(name: 'idx_knowledge_tag_label', columns: ['label'])]
|
||||
class Tag
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'uuid', unique: true)]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 120, unique: true)]
|
||||
private string $slug;
|
||||
|
||||
#[ORM\Column(length: 180)]
|
||||
private string $label;
|
||||
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $description = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private \DateTimeImmutable $createdAt;
|
||||
|
||||
public function __construct(string $slug, string $label, ?string $description = null)
|
||||
{
|
||||
$this->id = Uuid::v4();
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
|
||||
$this->slug = $slug;
|
||||
$this->label = $label;
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
public function getId(): Uuid
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getSlug(): string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function setSlug(string $slug): static
|
||||
{
|
||||
$this->slug = $slug;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $label): static
|
||||
{
|
||||
$this->label = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDescription(): ?string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function setDescription(?string $description): static
|
||||
{
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
}
|
||||
96
src/Entity/TagRebuildJob.php
Normal file
96
src/Entity/TagRebuildJob.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[ORM\Table(name: 'tag_rebuild_job')]
|
||||
#[ORM\Index(columns: ['status'], name: 'idx_tag_rebuild_job_status')]
|
||||
#[ORM\Index(columns: ['created_at'], name: 'idx_tag_rebuild_job_created_at')]
|
||||
class TagRebuildJob
|
||||
{
|
||||
public const STATUS_QUEUED = 'QUEUED';
|
||||
public const STATUS_RUNNING = 'RUNNING';
|
||||
public const STATUS_COMPLETED = 'COMPLETED';
|
||||
public const STATUS_FAILED = 'FAILED';
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\Column(type: 'uuid', unique: true)]
|
||||
private Uuid $id;
|
||||
|
||||
#[ORM\Column(length: 16)]
|
||||
private string $status = self::STATUS_QUEUED;
|
||||
|
||||
#[ORM\Column(type: 'datetime_immutable')]
|
||||
private \DateTimeImmutable $createdAt;
|
||||
|
||||
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
|
||||
private ?\DateTimeImmutable $startedAt = null;
|
||||
|
||||
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
|
||||
private ?\DateTimeImmutable $finishedAt = null;
|
||||
|
||||
#[ORM\Column(type: 'text', nullable: true)]
|
||||
private ?string $errorMessage = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->id = Uuid::v4();
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
$this->status = self::STATUS_QUEUED;
|
||||
}
|
||||
|
||||
public function getId(): Uuid
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getStatus(): string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function markRunning(): void
|
||||
{
|
||||
$this->status = self::STATUS_RUNNING;
|
||||
$this->startedAt = new \DateTimeImmutable();
|
||||
$this->errorMessage = null;
|
||||
}
|
||||
|
||||
public function markCompleted(): void
|
||||
{
|
||||
$this->status = self::STATUS_COMPLETED;
|
||||
$this->finishedAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function markFailed(string $message): void
|
||||
{
|
||||
$this->status = self::STATUS_FAILED;
|
||||
$this->finishedAt = new \DateTimeImmutable();
|
||||
$this->errorMessage = $message;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function getStartedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->startedAt;
|
||||
}
|
||||
|
||||
public function getFinishedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->finishedAt;
|
||||
}
|
||||
|
||||
public function getErrorMessage(): ?string
|
||||
{
|
||||
return $this->errorMessage;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user