src/Entity/WorksPlan.php line 24

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Repository\WorksPlanRepository;
  4. use Doctrine\Common\Collections\ArrayCollection;
  5. use Doctrine\Common\Collections\Collection;
  6. use Doctrine\ORM\Mapping as ORM;
  7. use Symfony\Component\Serializer\Annotation\Context;
  8. use Symfony\Component\Serializer\Annotation\Groups;
  9. /**
  10.  * WorksPlan — bir order'a bind edilebilen ya da bağımsız çalışan iş planı.
  11.  *
  12.  * Plan otorite olduğunda task/job strüktürünü taşır, dependency DAG'ı yönetir,
  13.  * cascade hesabını yapar. Order'a bind edilince ProjectOrderTasks/ProjectOrderTaskJobs
  14.  * satırları Plan'ın aynası haline gelir (MaterializationListener). Order'daki end_at
  15.  * Plan'a is_end_at olarak geri akar (OrderEndAtBackSyncListener).
  16.  *
  17.  * @ORM\Entity(repositoryClass=WorksPlanRepository::class)
  18.  * @ORM\Table(name="works_plan")
  19.  * @ORM\HasLifecycleCallbacks
  20.  */
  21. class WorksPlan
  22. {
  23.     /**
  24.      * @ORM\Id
  25.      * @ORM\GeneratedValue
  26.      * @ORM\Column(type="integer")
  27.      * @Groups({
  28.      *     "works_plan@ref",
  29.      *     "works_plan@base",
  30.      *     "works_plan@core",
  31.      *     "works_plan@list"
  32.      * })
  33.      */
  34.     private $id;
  35.     /**
  36.      * @ORM\Column(type="string", length=255)
  37.      * @Groups({
  38.      *     "works_plan@base",
  39.      *     "works_plan@core",
  40.      *     "works_plan@list"
  41.      * })
  42.      */
  43.     private $title;
  44.     /**
  45.      * @ORM\Column(type="text", nullable=true)
  46.      * @Groups({
  47.      *     "works_plan@core",
  48.      *     "works_plan@list"
  49.      * })
  50.      */
  51.     private $description;
  52.     /**
  53.      * Bağlı order — UNIQUE OneToOne (tek yönlü). ProjectOrders.works_plan ile çift bağ
  54.      * BindService tarafından synchronize edilir.
  55.      *
  56.      * @ORM\OneToOne(targetEntity=ProjectOrders::class)
  57.      * @ORM\JoinColumn(name="project_order_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  58.      * @Groups({
  59.      *     "works_plan@core",
  60.      *     "works_plan@list"
  61.      * })
  62.      */
  63.     private $project_order;
  64.     /**
  65.      * @ORM\ManyToOne(targetEntity=WorkerActivities::class)
  66.      * @ORM\JoinColumn(name="owner_id", referencedColumnName="id", nullable=true)
  67.      * @Groups({
  68.      *     "works_plan@core",
  69.      *     "works_plan@list"
  70.      * })
  71.      */
  72.     private $owner;
  73.     /**
  74.      * @ORM\Column(type="datetime_immutable")
  75.      * @Groups({
  76.      *     "works_plan@core",
  77.      *     "works_plan@list"
  78.      * })
  79.      */
  80.     private $created_at;
  81.     /**
  82.      * @ORM\Column(type="datetime_immutable", nullable=true)
  83.      * @Groups({
  84.      *     "works_plan@core",
  85.      *     "works_plan@list"
  86.      * })
  87.      */
  88.     private $updated_at;
  89.     /**
  90.      * #71 Faz 2 — Plan kilit tarihi (SADECE owner belirler). Bu tarihten SONRA (lazy: now > lock_at) plan
  91.      * kilitlenir → yalnız plan owner DOĞRUDAN düzenler; paydaşlar revizyon akışından geçer (Faz 3).
  92.      * NULL = kilit ayarlanmamış (süresiz serbest). Auto-lock bir DB state-transition DEĞİL — serialize'daki
  93.      * is_locked bunu hesaplar; owner lock_at'i ileri çekince plan kendiliğinden yeniden açılır (uzatma).
  94.      *
  95.      * @ORM\Column(type="datetime_immutable", nullable=true)
  96.      * @Context({"datetime_format"="c"})
  97.      * @Groups({
  98.      *     "works_plan@core",
  99.      *     "works_plan@list"
  100.      * })
  101.      */
  102.     private $lock_at;
  103.     /**
  104.      * @ORM\OneToMany(targetEntity=WorksPlanTask::class, mappedBy="works_plan", cascade={"persist"}, orphanRemoval=true)
  105.      * @ORM\OrderBy({"task_index" = "ASC"})
  106.      * @Groups({
  107.      *     "works_plan@tasks"
  108.      * })
  109.      */
  110.     private $tasks;
  111.     /**
  112.      * Plan paydaşları (#71) — bu planı görebilen + task üstlenebilen worker activities.
  113.      * Havuz = worker_activities (owner ile aynı tip). Owner service'te otomatik paydaş sayılır.
  114.      *
  115.      * @ORM\ManyToMany(targetEntity=WorkerActivities::class)
  116.      * @ORM\JoinTable(name="works_plan_stakeholders",
  117.      *     joinColumns={@ORM\JoinColumn(name="works_plan_id", referencedColumnName="id", onDelete="CASCADE")},
  118.      *     inverseJoinColumns={@ORM\JoinColumn(name="worker_activity_id", referencedColumnName="id", onDelete="CASCADE")}
  119.      * )
  120.      * @Groups({
  121.      *     "works_plan@core"
  122.      * })
  123.      */
  124.     private $stakeholders;
  125.     public function __construct()
  126.     {
  127.         $this->tasks = new ArrayCollection();
  128.         $this->stakeholders = new ArrayCollection();
  129.     }
  130.     /**
  131.      * @ORM\PrePersist
  132.      */
  133.     public function onPrePersist(): void
  134.     {
  135.         if ($this->created_at === null) {
  136.             $this->created_at = new \DateTimeImmutable();
  137.         }
  138.     }
  139.     /**
  140.      * @ORM\PreUpdate
  141.      */
  142.     public function onPreUpdate(): void
  143.     {
  144.         $this->updated_at = new \DateTimeImmutable();
  145.     }
  146.     public function getId(): ?int
  147.     {
  148.         return $this->id;
  149.     }
  150.     public function getTitle(): ?string
  151.     {
  152.         return $this->title;
  153.     }
  154.     public function setTitle(string $title): self
  155.     {
  156.         $this->title $title;
  157.         return $this;
  158.     }
  159.     public function getDescription(): ?string
  160.     {
  161.         return $this->description;
  162.     }
  163.     public function setDescription(?string $description): self
  164.     {
  165.         $this->description $description;
  166.         return $this;
  167.     }
  168.     public function getProjectOrder(): ?ProjectOrders
  169.     {
  170.         return $this->project_order;
  171.     }
  172.     public function setProjectOrder(?ProjectOrders $project_order): self
  173.     {
  174.         $this->project_order $project_order;
  175.         return $this;
  176.     }
  177.     public function getOwner(): ?WorkerActivities
  178.     {
  179.         return $this->owner;
  180.     }
  181.     public function setOwner(?WorkerActivities $owner): self
  182.     {
  183.         $this->owner $owner;
  184.         return $this;
  185.     }
  186.     public function getCreatedAt(): ?\DateTimeImmutable
  187.     {
  188.         return $this->created_at;
  189.     }
  190.     public function setCreatedAt(\DateTimeImmutable $created_at): self
  191.     {
  192.         $this->created_at $created_at;
  193.         return $this;
  194.     }
  195.     public function getUpdatedAt(): ?\DateTimeImmutable
  196.     {
  197.         return $this->updated_at;
  198.     }
  199.     public function setUpdatedAt(?\DateTimeImmutable $updated_at): self
  200.     {
  201.         $this->updated_at $updated_at;
  202.         return $this;
  203.     }
  204.     public function getLockAt(): ?\DateTimeImmutable
  205.     {
  206.         return $this->lock_at;
  207.     }
  208.     public function setLockAt(?\DateTimeImmutable $lock_at): self
  209.     {
  210.         $this->lock_at $lock_at;
  211.         return $this;
  212.     }
  213.     /**
  214.      * #71 Faz 2 — Lazy kilit hesabı (cron YOK): lock_at ayarlıysa ve geçmişse plan kilitli.
  215.      * Kilitliyken yalnız plan owner doğrudan düzenler; paydaşlar revizyon akışından geçer.
  216.      */
  217.     public function isLocked(): bool
  218.     {
  219.         return $this->lock_at !== null && $this->lock_at < new \DateTimeImmutable();
  220.     }
  221.     /**
  222.      * Reindex edilmiş tasks collection — Serializer'ın associative object çıkarmasını
  223.      * engeller (bkz. ProjectOrderTasks::getTaskJobs() yorumu).
  224.      *
  225.      * @return Collection<int, WorksPlanTask>
  226.      */
  227.     public function getTasks(): Collection
  228.     {
  229.         return new ArrayCollection(array_values($this->tasks->toArray()));
  230.     }
  231.     public function addTask(WorksPlanTask $task): self
  232.     {
  233.         if (!$this->tasks->contains($task)) {
  234.             $this->tasks[] = $task;
  235.             $task->setWorksPlan($this);
  236.         }
  237.         return $this;
  238.     }
  239.     public function removeTask(WorksPlanTask $task): self
  240.     {
  241.         if ($this->tasks->removeElement($task)) {
  242.             if ($task->getWorksPlan() === $this) {
  243.                 $task->setWorksPlan(null);
  244.             }
  245.         }
  246.         return $this;
  247.     }
  248.     /**
  249.      * Reindex edilmiş paydaş collection (associative object çıkmasını engeller).
  250.      *
  251.      * @return Collection<int, WorkerActivities>
  252.      */
  253.     public function getStakeholders(): Collection
  254.     {
  255.         return new ArrayCollection(array_values($this->stakeholders->toArray()));
  256.     }
  257.     public function addStakeholder(WorkerActivities $workerActivity): self
  258.     {
  259.         if (!$this->stakeholders->contains($workerActivity)) {
  260.             $this->stakeholders[] = $workerActivity;
  261.         }
  262.         return $this;
  263.     }
  264.     public function removeStakeholder(WorkerActivities $workerActivity): self
  265.     {
  266.         $this->stakeholders->removeElement($workerActivity);
  267.         return $this;
  268.     }
  269.     public function clearStakeholders(): self
  270.     {
  271.         $this->stakeholders->clear();
  272.         return $this;
  273.     }
  274. }