<?php
namespace App\Entity;
use App\Repository\UserServiceAccessRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* KULLANICI <-> SERVIS erisim kaydi.
*
* KAYDIN YOKLUGU DA BIR ANLAM TASIR — bu tablonun en kritik ozelligi budur:
* kayit yok -> servisin is_default degeri gecerlidir (ERP: acik, digerleri: kapali)
* granted=0 -> ACIKCA YASAK (ERP'ye bile giremez)
* granted=1 -> ACIKCA IZINLI
*
* Yani "izin = satir varligi" DEGILDIR; bu yuzden granted BOOLEAN tutulur (kullanici
* karari 2026-08-21). Aksi halde bir kullaniciya ERP'yi KAPATMAK mumkun olmazdi.
*
* (user, service) cifti benzersizdir — bir kullanicinin bir servis icin tek karari olur.
*
* @ORM\Entity(repositoryClass=UserServiceAccessRepository::class)
* @ORM\Table(
* name="user_service_access",
* uniqueConstraints={
* @ORM\UniqueConstraint(name="uniq_user_service", columns={"user_id", "service_id"})
* }
* )
* @ORM\HasLifecycleCallbacks
*/
class UserServiceAccess
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
* @Groups({
* "user_service_access@ref",
* "user_service_access@base",
* "user_service_access@core"
* })
*/
private $id;
/**
* Kullanici bazli OZELLIK haklari (AI Hub: model_picker, voice_mode ...). Satir yok = hak yok.
* @ORM\OneToMany(targetEntity=UserServiceFeature::class, mappedBy="user_service_access", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $features;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="service_accesses")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
* @Groups({
* "user_service_access@user"
* })
*/
private $user;
/**
* @ORM\ManyToOne(targetEntity=Services::class, inversedBy="user_accesses")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
* @Groups({
* "user_service_access@base",
* "user_service_access@core"
* })
*/
private $service;
/**
* Acik karar: true = erisir, false = ERISEMEZ (servis default acik olsa bile).
* @ORM\Column(type="boolean", nullable=false, options={"default": false})
* @Groups({
* "user_service_access@base",
* "user_service_access@core"
* })
*/
private $granted = false;
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
* @Groups({
* "user_service_access@core"
* })
*/
private $created_at;
/**
* @ORM\Column(type="datetime_immutable", nullable=true)
* @Groups({
* "user_service_access@core"
* })
*/
private $updated_at;
/**
* @ORM\PrePersist
*/
public function onPrePersist(): void
{
if ($this->created_at === null) {
$this->created_at = new \DateTimeImmutable();
}
$this->updated_at = new \DateTimeImmutable();
}
/**
* @ORM\PreUpdate
*/
public function onPreUpdate(): void
{
$this->updated_at = new \DateTimeImmutable();
}
public function __construct()
{
$this->features = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getService(): ?Services
{
return $this->service;
}
public function setService(?Services $service): self
{
$this->service = $service;
return $this;
}
public function getGranted(): ?bool
{
return $this->granted;
}
public function setGranted(bool $granted): self
{
$this->granted = $granted;
return $this;
}
public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->created_at;
}
public function setCreatedAt(?\DateTimeImmutable $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getUpdatedAt(): ?\DateTimeImmutable
{
return $this->updated_at;
}
public function setUpdatedAt(?\DateTimeImmutable $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}
/** @return Collection<int, UserServiceFeature> */
public function getFeatures(): Collection
{
return $this->features;
}
public function addFeature(UserServiceFeature $feature): self
{
if (!$this->features->contains($feature)) {
$this->features[] = $feature;
$feature->setUserServiceAccess($this);
}
return $this;
}
}