['client_ticket:read']], denormalizationContext: ['groups' => ['client_ticket:write']], order: ['createdAt' => 'DESC'], )] #[ApiFilter(SearchFilter::class, properties: ['project' => 'exact', 'status' => 'exact', 'submittedBy' => 'exact'])] #[Auditable] #[ORM\Entity(repositoryClass: DoctrineClientTicketRepository::class)] #[ORM\Table(name: 'client_ticket')] #[ORM\UniqueConstraint(name: 'uniq_client_ticket_project_number', columns: ['project_id', 'number'])] #[ORM\Index(name: 'idx_client_ticket_project', columns: ['project_id'])] #[ORM\Index(name: 'idx_client_ticket_submitted_by', columns: ['submitted_by_id'])] #[ORM\Index(name: 'idx_client_ticket_status_project', columns: ['status', 'project_id'])] class ClientTicket implements ClientTicketInterface, TimestampableInterface, BlamableInterface { use TimestampableBlamableTrait; #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] #[Groups(['client_ticket:read', 'task:read'])] private ?int $id = null; /** Incremental number, unique per project (formatted CT-XXX in the UI). */ #[ORM\Column(type: 'integer')] #[Groups(['client_ticket:read', 'task:read'])] private ?int $number = null; #[ORM\Column(type: 'string', length: 16, enumType: ClientTicketType::class)] #[Groups(['client_ticket:read', 'client_ticket:write', 'task:read'])] #[Assert\NotNull] private ?ClientTicketType $type = null; #[ORM\Column(length: 255)] #[Groups(['client_ticket:read', 'client_ticket:write', 'task:read'])] #[Assert\NotBlank] private ?string $title = null; #[ORM\Column(type: 'text')] #[Groups(['client_ticket:read', 'client_ticket:write'])] #[Assert\NotBlank] private ?string $description = null; /** Displayed only when type = bug (page concerned by the bug). */ #[ORM\Column(length: 1024, nullable: true)] #[Groups(['client_ticket:read', 'client_ticket:write'])] private ?string $url = null; #[ORM\Column(type: 'string', length: 16, enumType: ClientTicketStatus::class)] #[Groups(['client_ticket:read', 'client_ticket:write', 'task:read'])] private ClientTicketStatus $status = ClientTicketStatus::New; /** Manager comment set when the status changes (mandatory when rejecting). */ #[ORM\Column(type: 'text', nullable: true)] #[Groups(['client_ticket:read', 'client_ticket:write'])] private ?string $statusComment = null; #[ORM\ManyToOne(targetEntity: ProjectInterface::class)] #[ORM\JoinColumn(name: 'project_id', nullable: false, onDelete: 'CASCADE')] #[Groups(['client_ticket:read', 'client_ticket:write'])] #[Assert\NotNull] private ?ProjectInterface $project = null; /** Client user who submitted the ticket. ON DELETE SET NULL — keep history. */ #[ORM\ManyToOne(targetEntity: UserInterface::class)] #[ORM\JoinColumn(name: 'submitted_by_id', nullable: true, onDelete: 'SET NULL')] #[Groups(['client_ticket:read'])] private ?UserInterface $submittedBy = null; public function getId(): ?int { return $this->id; } public function getNumber(): ?int { return $this->number; } public function setNumber(int $number): static { $this->number = $number; return $this; } public function getTypeEnum(): ?ClientTicketType { return $this->type; } public function setType(?ClientTicketType $type): static { $this->type = $type; return $this; } public function getType(): string { return $this->type?->value ?? ''; } public function getTitle(): ?string { return $this->title; } public function setTitle(?string $title): static { $this->title = $title; return $this; } public function getDescription(): ?string { return $this->description; } public function setDescription(?string $description): static { $this->description = $description; return $this; } public function getUrl(): ?string { return $this->url; } public function setUrl(?string $url): static { $this->url = $url; return $this; } public function getStatusEnum(): ClientTicketStatus { return $this->status; } public function setStatus(ClientTicketStatus $status): static { $this->status = $status; return $this; } public function getStatus(): string { return $this->status->value; } public function getStatusComment(): ?string { return $this->statusComment; } public function setStatusComment(?string $statusComment): static { $this->statusComment = $statusComment; return $this; } public function getProject(): ?ProjectInterface { return $this->project; } public function setProject(?ProjectInterface $project): static { $this->project = $project; return $this; } public function getSubmittedBy(): ?UserInterface { return $this->submittedBy; } public function setSubmittedBy(?UserInterface $submittedBy): static { $this->submittedBy = $submittedBy; return $this; } }