src/Entity/ProjectOrderTasks.php line 15

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Repository\ProjectOrderTasksRepository;
  4. use Doctrine\Common\Collections\ArrayCollection;
  5. use Doctrine\Common\Collections\Collection;
  6. use Doctrine\Common\Collections\Selectable;
  7. use Doctrine\ORM\Mapping as ORM;
  8. use Symfony\Component\Serializer\Annotation\Groups;
  9. /**
  10.  * @ORM\Entity(repositoryClass=ProjectOrderTasksRepository::class)
  11.  */
  12. class ProjectOrderTasks
  13. {
  14.     /**
  15.      * @ORM\Id
  16.      * @ORM\GeneratedValue
  17.      * @ORM\Column(type="integer")
  18.      * @Groups({
  19.      *     "project_order_task@base",
  20.      *     "project_order_task@core"
  21.      * })
  22.      */
  23.     private $id;
  24.     /**
  25.      * @ORM\Column(type="integer")
  26.      * @Groups({
  27.      *      "project_order_task@base",
  28.      *      "project_order_task@core"
  29.      *  })
  30.      */
  31.     private $task_index;
  32.     /**
  33.      * @ORM\Column(type="string", length=255)
  34.      * @Groups({
  35.      *      "project_order_task@base",
  36.      *      "project_order_task@core"
  37.      *  })
  38.      */
  39.     private $title;
  40.     /**
  41.      * @ORM\Column(type="text", nullable=true)
  42.      * @Groups({
  43.      *      "project_order_task@base",
  44.      *      "project_order_task@core"
  45.      *  })
  46.      */
  47.     private $description;
  48.     /**
  49.      * @ORM\Column(type="float")
  50.      * @Groups({
  51.      *      "project_order_task@core"
  52.      *  })
  53.      */
  54.     private $progress_weight;
  55.     /**
  56.      * @ORM\Column(type="integer", nullable=true)
  57.      * @Groups({
  58.      *      "project_order_task@core"
  59.      *  })
  60.      */
  61.     private $duration_days;
  62.     /**
  63.      * @deprecated never use this controlling over job
  64.      * @ORM\Column(type="date_immutable", nullable=true, options={"comment": "deprecated -> Redundant field; value is dynamically calculated based on completed job weights."})
  65.      * @Groups({
  66.      *      "project_order_task@core"
  67.      *  })
  68.      */
  69.     private $started_at;
  70.     /**
  71.      * @deprecated never use this controlling over job
  72.      * @ORM\Column(type="date_immutable", nullable=true, options={"comment": "deprecated -> Redundant field; value is dynamically calculated based on completed job weights."})
  73.      * @Groups({
  74.      *      "project_order_task@core"
  75.      *  })
  76.      */
  77.     private $completed_at;
  78.     /**
  79.      * @ORM\ManyToOne(targetEntity=ProjectOrders::class, inversedBy="project_order_tasks")
  80.      * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
  81.      */
  82.     private $project_order;
  83.     /**
  84.      * @ORM\OneToMany(targetEntity=ProjectOrderTaskJobs::class, mappedBy="order_task", cascade={"persist"}, orphanRemoval=true )
  85.      * @Groups({
  86.      *       "project_order_task@task_jobs"
  87.      *   })
  88.      */
  89.     private $task_jobs;
  90.     /**
  91.      * @ORM\OneToOne(targetEntity=ProjectOrderTaskFulfillment::class, mappedBy="task", cascade={"persist", "remove"})
  92.      * @Groups({
  93.      *     "project_order_task@fulfillment"
  94.      * })
  95.      */
  96.     private $task_fulfillment;
  97.     /**
  98.      * @ORM\ManyToOne(targetEntity=WorkerActivities::class, inversedBy="project_order_tasks")
  99.      * @Groups({
  100.      *         "project_order_task@responsible_person"
  101.      *  })
  102.      */
  103.     private $responsible_person;
  104.     public function __construct()
  105.     {
  106.         $this->task_jobs = new ArrayCollection();
  107.     }
  108.     public function getId(): ?int
  109.     {
  110.         return $this->id;
  111.     }
  112.     public function getTaskIndex(): ?int
  113.     {
  114.         return $this->task_index;
  115.     }
  116.     public function setTaskIndex(int $task_index): self
  117.     {
  118.         $this->task_index $task_index;
  119.         return $this;
  120.     }
  121.     public function getTitle(): ?string
  122.     {
  123.         return $this->title;
  124.     }
  125.     public function setTitle(string $title): self
  126.     {
  127.         $this->title $title;
  128.         return $this;
  129.     }
  130.     public function getDescription(): ?string
  131.     {
  132.         return $this->description;
  133.     }
  134.     public function setDescription(?string $description): self
  135.     {
  136.         $this->description $description;
  137.         return $this;
  138.     }
  139.     public function getProgressWeight(): ?float
  140.     {
  141.         return $this->progress_weight;
  142.     }
  143.     public function setProgressWeight(float $progress_weight): self
  144.     {
  145.         $this->progress_weight $progress_weight;
  146.         return $this;
  147.     }
  148.     public function getDurationDays(): ?int
  149.     {
  150.         return $this->duration_days;
  151.     }
  152.     public function setDurationDays(?int $duration_days): self
  153.     {
  154.         $this->duration_days $duration_days;
  155.         return $this;
  156.     }
  157.     public function getStartedAt(): ?\DateTimeImmutable
  158.     {
  159.         return $this->started_at;
  160.     }
  161.     public function setStartedAt(?\DateTimeImmutable $started_at): self
  162.     {
  163.         $this->started_at $started_at;
  164.         return $this;
  165.     }
  166.     public function getCompletedAt(): ?\DateTimeImmutable
  167.     {
  168.         return $this->completed_at;
  169.     }
  170.     public function setCompletedAt(?\DateTimeImmutable $completed_at): self
  171.     {
  172.         $this->completed_at $completed_at;
  173.         return $this;
  174.     }
  175.     public function getProjectOrder(): ?ProjectOrders
  176.     {
  177.         return $this->project_order;
  178.     }
  179.     public function setProjectOrder(?ProjectOrders $project_order): self
  180.     {
  181.         $this->project_order $project_order;
  182.         return $this;
  183.     }
  184.     /**
  185.      * /**
  186.      *  ⚠️ IMPORTANT – Collection index / Serializer issue
  187.      *
  188.      *  Problem:
  189.      *  --------
  190.      *  ProjectOrderTaskJobs koleksiyonu (Doctrine ArrayCollection) üzerinde
  191.      *  BİRDEN FAZLA remove işlemi yapıldığında, Doctrine elemanları silerken
  192.      *  array indexlerini yeniden sıralamaz.
  193.      *
  194.      *  Örnek:
  195.      *    [0 => JobA, 1 => JobB, 2 => JobC]
  196.      *    JobB silinirse →
  197.      *    [0 => JobA, 2 => JobC]   // index boşluğu oluşur ❌
  198.      *
  199.      *  Symfony Serializer bu yapıyı:
  200.      *    - indexler ardışık değilse → associative object `{}` olarak,
  201.      *    - indexler 0..n ise → JSON array `[]` olarak serialize eder.
  202.      *
  203.      *  Bu nedenle çoklu silme sonrası FE tarafında:
  204.      *    task_jobs: { "1": {...} }
  205.      *  gibi HATALI bir çıktı oluşur.
  206.      *
  207.      *  Çözüm:
  208.      *  ------
  209.      *  Serializer'a gönderilmeden önce collection MUTLAKA reindex edilmelidir.
  210.      *  Bu da getter seviyesinde yapılır:
  211.      *
  212.      *    return new ArrayCollection(array_values($this->task_jobs->toArray()));
  213.      *
  214.      *  Böylece:
  215.      *    - Doctrine iç davranışı bozulmaz
  216.      *    - Serializer her zaman `[...]` JSON array üretir
  217.      *    - FE tarafında index problemi yaşanmaz
  218.      *
  219.      *  Not:
  220.      *  ----
  221.      *  Bu problem serializer flag'leri (preserve_empty_objects vb.)
  222.      *  ile çözülemez; sorun serialization değil, collection index yapısıdır.
  223.      * /
  224.      * @return Collection<int, ProjectOrderTaskJobs>&Selectable
  225.      */
  226.     public function getTaskJobs(): Collection
  227.     {
  228.         return new ArrayCollection(array_values($this->task_jobs->toArray()));
  229.     }
  230.     public function addProjectOrderTaskJob(ProjectOrderTaskJobs $projectOrderTaskJob): self
  231.     {
  232.         if (!$this->task_jobs->contains($projectOrderTaskJob)) {
  233.             $this->task_jobs[] = $projectOrderTaskJob;
  234.             $projectOrderTaskJob->setOrderTask($this);
  235.         }
  236.         return $this;
  237.     }
  238.     /**
  239.      * @see ProjectOrderTasks::getTaskJobs()
  240.     */
  241.     public function removeProjectOrderTaskJob(ProjectOrderTaskJobs $projectOrderTaskJob): self
  242.     {
  243.         if ($this->task_jobs->removeElement($projectOrderTaskJob)) {
  244.             // set the owning side to null (unless already changed)
  245.             if ($projectOrderTaskJob->getOrderTask() === $this) {
  246.                 $projectOrderTaskJob->setOrderTask(null);
  247.             }
  248.         }
  249.         return $this;
  250.     }
  251.     public function getTaskFulfillment(): ?ProjectOrderTaskFulfillment
  252.     {
  253.         return $this->task_fulfillment;
  254.     }
  255.     public function setTaskFulfillment(?ProjectOrderTaskFulfillment $task_fulfillment): self
  256.     {
  257.         // set the owning side of the relation if necessary
  258.         if ($task_fulfillment->getTask() !== $this) {
  259.             $task_fulfillment->setTask($this);
  260.         }
  261.         $this->task_fulfillment $task_fulfillment;
  262.         return $this;
  263.     }
  264.     public function getResponsiblePerson(): ?WorkerActivities
  265.     {
  266.         return $this->responsible_person;
  267.     }
  268.     public function setResponsiblePerson(?WorkerActivities $responsible_person): self
  269.     {
  270.         $this->responsible_person $responsible_person;
  271.         return $this;
  272.     }
  273. }