- Add Assert\Choice on ClientTicket type and status with typed constants - Add Assert\Url on GiteaConfiguration, BookStackConfiguration, TaskBookStackLink, ClientTicket - Fix concurrent task/ticket numbering: use pg_advisory_xact_lock instead of FOR UPDATE with MAX() - Wrap CreateTaskTool numbering in transaction - Harmonize repository contracts: both return max number, caller adds +1 Tickets: T-004, T-008, T-011, T-012 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
116 lines
2.2 KiB
PHP
116 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Entity;
|
|
|
|
use App\Repository\TaskBookStackLinkRepository;
|
|
use DateTimeImmutable;
|
|
use Doctrine\ORM\Mapping as ORM;
|
|
use Symfony\Component\Validator\Constraints as Assert;
|
|
|
|
#[ORM\Entity(repositoryClass: TaskBookStackLinkRepository::class)]
|
|
#[ORM\UniqueConstraint(name: 'UNIQ_task_bookstack_link', columns: ['task_id', 'bookstack_id', 'bookstack_type'])]
|
|
class TaskBookStackLink
|
|
{
|
|
#[ORM\Id]
|
|
#[ORM\GeneratedValue]
|
|
#[ORM\Column]
|
|
private ?int $id = null;
|
|
|
|
#[ORM\ManyToOne(targetEntity: Task::class)]
|
|
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
|
private Task $task;
|
|
|
|
#[ORM\Column]
|
|
private int $bookstackId;
|
|
|
|
#[ORM\Column(length: 10)]
|
|
private string $bookstackType;
|
|
|
|
#[ORM\Column(length: 255)]
|
|
private string $title;
|
|
|
|
#[ORM\Column(length: 500)]
|
|
#[Assert\Url]
|
|
private string $url;
|
|
|
|
#[ORM\Column]
|
|
private DateTimeImmutable $createdAt;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->createdAt = new DateTimeImmutable();
|
|
}
|
|
|
|
public function getId(): ?int
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
public function getTask(): Task
|
|
{
|
|
return $this->task;
|
|
}
|
|
|
|
public function setTask(Task $task): static
|
|
{
|
|
$this->task = $task;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getBookstackId(): int
|
|
{
|
|
return $this->bookstackId;
|
|
}
|
|
|
|
public function setBookstackId(int $bookstackId): static
|
|
{
|
|
$this->bookstackId = $bookstackId;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getBookstackType(): string
|
|
{
|
|
return $this->bookstackType;
|
|
}
|
|
|
|
public function setBookstackType(string $bookstackType): static
|
|
{
|
|
$this->bookstackType = $bookstackType;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getTitle(): string
|
|
{
|
|
return $this->title;
|
|
}
|
|
|
|
public function setTitle(string $title): static
|
|
{
|
|
$this->title = $title;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getUrl(): string
|
|
{
|
|
return $this->url;
|
|
}
|
|
|
|
public function setUrl(string $url): static
|
|
{
|
|
$this->url = $url;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getCreatedAt(): DateTimeImmutable
|
|
{
|
|
return $this->createdAt;
|
|
}
|
|
}
|