Create Comment entity with API Platform annotations (GET, PATCH, DELETE). Add CommentController with POST (create), PATCH (resolve) and GET (unresolved count) endpoints. Add migration for comments table and piece reference unique index. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
236 lines
5.6 KiB
PHP
236 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Entity;
|
|
|
|
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
|
|
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
|
use ApiPlatform\Metadata\ApiFilter;
|
|
use ApiPlatform\Metadata\ApiResource;
|
|
use ApiPlatform\Metadata\Delete;
|
|
use ApiPlatform\Metadata\Get;
|
|
use ApiPlatform\Metadata\GetCollection;
|
|
use ApiPlatform\Metadata\Patch;
|
|
use DateTimeImmutable;
|
|
use Doctrine\DBAL\Types\Types;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
|
|
#[ORM\Entity]
|
|
#[ORM\Table(name: 'comments')]
|
|
#[ORM\Index(columns: ['entity_type', 'entity_id', 'status'], name: 'idx_comment_entity_status')]
|
|
#[ORM\HasLifecycleCallbacks]
|
|
#[ApiFilter(SearchFilter::class, properties: ['entityType' => 'exact', 'entityId' => 'exact', 'status' => 'exact'])]
|
|
#[ApiFilter(OrderFilter::class, properties: ['createdAt'])]
|
|
#[ApiResource(
|
|
operations: [
|
|
new Get(security: "is_granted('ROLE_VIEWER')"),
|
|
new GetCollection(security: "is_granted('ROLE_VIEWER')"),
|
|
new Patch(security: "is_granted('ROLE_GESTIONNAIRE')"),
|
|
new Delete(security: "is_granted('ROLE_GESTIONNAIRE')"),
|
|
],
|
|
order: ['createdAt' => 'DESC'],
|
|
paginationClientItemsPerPage: true,
|
|
paginationMaximumItemsPerPage: 200
|
|
)]
|
|
class Comment
|
|
{
|
|
#[ORM\Id]
|
|
#[ORM\Column(type: Types::STRING, length: 36)]
|
|
private ?string $id = null;
|
|
|
|
#[ORM\Column(type: Types::TEXT)]
|
|
private string $content;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 50, name: 'entity_type')]
|
|
private string $entityType;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 36, name: 'entity_id')]
|
|
private string $entityId;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 255, nullable: true, name: 'entity_name')]
|
|
private ?string $entityName = null;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 36, name: 'author_id')]
|
|
private string $authorId;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 255, name: 'author_name')]
|
|
private string $authorName;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 20)]
|
|
private string $status = 'open';
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 36, nullable: true, name: 'resolved_by_id')]
|
|
private ?string $resolvedById = null;
|
|
|
|
#[ORM\Column(type: Types::STRING, length: 255, nullable: true, name: 'resolved_by_name')]
|
|
private ?string $resolvedByName = null;
|
|
|
|
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true, name: 'resolved_at')]
|
|
private ?DateTimeImmutable $resolvedAt = null;
|
|
|
|
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'created_at')]
|
|
private DateTimeImmutable $createdAt;
|
|
|
|
#[ORM\Column(type: Types::DATETIME_IMMUTABLE, name: 'updated_at')]
|
|
private DateTimeImmutable $updatedAt;
|
|
|
|
#[ORM\PrePersist]
|
|
public function setCreatedAtValue(): void
|
|
{
|
|
$now = new DateTimeImmutable();
|
|
$this->createdAt = $now;
|
|
$this->updatedAt = $now;
|
|
|
|
if (null === $this->id) {
|
|
$this->id = $this->generateCuid();
|
|
}
|
|
}
|
|
|
|
#[ORM\PreUpdate]
|
|
public function setUpdatedAtValue(): void
|
|
{
|
|
$this->updatedAt = new DateTimeImmutable();
|
|
}
|
|
|
|
public function getId(): ?string
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getContent(): string
|
|
{
|
|
return $this->content;
|
|
}
|
|
|
|
public function setContent(string $content): static
|
|
{
|
|
$this->content = $content;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getEntityType(): string
|
|
{
|
|
return $this->entityType;
|
|
}
|
|
|
|
public function setEntityType(string $entityType): static
|
|
{
|
|
$this->entityType = $entityType;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getEntityId(): string
|
|
{
|
|
return $this->entityId;
|
|
}
|
|
|
|
public function setEntityId(string $entityId): static
|
|
{
|
|
$this->entityId = $entityId;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getEntityName(): ?string
|
|
{
|
|
return $this->entityName;
|
|
}
|
|
|
|
public function setEntityName(?string $entityName): static
|
|
{
|
|
$this->entityName = $entityName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAuthorId(): string
|
|
{
|
|
return $this->authorId;
|
|
}
|
|
|
|
public function setAuthorId(string $authorId): static
|
|
{
|
|
$this->authorId = $authorId;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getAuthorName(): string
|
|
{
|
|
return $this->authorName;
|
|
}
|
|
|
|
public function setAuthorName(string $authorName): static
|
|
{
|
|
$this->authorName = $authorName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getStatus(): string
|
|
{
|
|
return $this->status;
|
|
}
|
|
|
|
public function setStatus(string $status): static
|
|
{
|
|
$this->status = $status;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getResolvedById(): ?string
|
|
{
|
|
return $this->resolvedById;
|
|
}
|
|
|
|
public function setResolvedById(?string $resolvedById): static
|
|
{
|
|
$this->resolvedById = $resolvedById;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getResolvedByName(): ?string
|
|
{
|
|
return $this->resolvedByName;
|
|
}
|
|
|
|
public function setResolvedByName(?string $resolvedByName): static
|
|
{
|
|
$this->resolvedByName = $resolvedByName;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getResolvedAt(): ?DateTimeImmutable
|
|
{
|
|
return $this->resolvedAt;
|
|
}
|
|
|
|
public function setResolvedAt(?DateTimeImmutable $resolvedAt): static
|
|
{
|
|
$this->resolvedAt = $resolvedAt;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getCreatedAt(): DateTimeImmutable
|
|
{
|
|
return $this->createdAt;
|
|
}
|
|
|
|
public function getUpdatedAt(): DateTimeImmutable
|
|
{
|
|
return $this->updatedAt;
|
|
}
|
|
|
|
private function generateCuid(): string
|
|
{
|
|
return 'cl'.bin2hex(random_bytes(12));
|
|
}
|
|
}
|