src/Entity/Worker.php line 50

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use App\Repository\TimesheetStatusRepository;
  4. use App\Repository\WorkerRepository;
  5. use Doctrine\Common\Collections\ArrayCollection;
  6. use Doctrine\Common\Collections\Collection;
  7. use Doctrine\ORM\Event\LifecycleEventArgs;
  8. use Doctrine\ORM\Mapping as ORM;
  9. use phpDocumentor\Reflection\Types\This;
  10. use Monolog\DateTimeImmutable;
  11. use PhpParser\ErrorHandler\Collecting;
  12. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Entity;
  13. use Symfony\Component\Validator\Constraints\DateTime;
  14. use Symfony\Component\Serializer\Annotation\MaxDepth;
  15. use Symfony\Component\Serializer\Annotation\Groups;
  16. use Gedmo\Mapping\Annotation as Gedmo;
  17. use Doctrine\ORM\Mapping\Table;
  18. use Doctrine\ORM\Mapping\UniqueConstraint;
  19. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  20. use Doctrine\Common\Collections\Criteria;
  21. /**
  22.  * @ORM\Entity(repositoryClass=WorkerRepository::class)
  23.  */
  24. /**
  25.  * @ORM\HasLifecycleCallbacks
  26.  * @ORM\Entity(repositoryClass=WorkerRepository::class)
  27.  * @ORM\Table(
  28.  *     name="worker",
  29.  *     uniqueConstraints={
  30.  *          @ORM\UniqueConstraint(columns={"name", "surname", "birthday_at"}),
  31.  *          @ORM\UniqueConstraint(name="unique_personal_id", columns={"personal_id"}, options={"where": "(personal_id IS NOT NULL)"}),
  32.  *          @ORM\UniqueConstraint(name="unique_social_insurance_number", columns={"social_insurance_number"}),
  33.  *     }
  34.  * )
  35.  * @UniqueEntity(
  36.  *      fields={"social_insurance_number"},
  37.  *      message="Social insurance number already registered|Social insurance number %4$s is already registered to another employee"
  38.  * )
  39.  * @UniqueEntity(
  40.  *      fields={"name", "surname", "birthday_at"},
  41.  *      message="Employee already registered|Employee with combination (%s %s %s) is already registered"
  42.  * )
  43.  */
  44. class Worker
  45. {
  46.     // Same Process processed via Entity Subscriber
  47.     /**
  48.      * @ORM\Id
  49.      * @ORM\GeneratedValue
  50.      * @ORM\Column(type="integer")
  51.      * @Groups({
  52.      *     "worker.manage.base",
  53.      *     "partner.smart.active.employees",
  54.      *     "timesheet.for.stakeholder",
  55.      *     "worker.manage.base.timesheet",
  56.      *     "partner.selected.project",
  57.      * 
  58.      *     "project.details.orders",
  59.      *     "order.detail",
  60.      *     "order.lead",
  61.      *
  62.      *     "timesheet.collected.base",
  63.      *
  64.      *     "worker.base",
  65.      *     "worker.core",
  66.      *
  67.      *     "worker.activity.substitution.worker.activity.worker.core",
  68.      *
  69.      *     "worker@ref",
  70.      *     "worker@core",
  71.      *     "worker@base",
  72.      * })
  73.      */
  74.     private $id;
  75.     /**
  76.      * TODO replace base with core
  77.      * @ORM\Column(type="string", length=255)
  78.      * @Groups({
  79.      *     "worker.manage.base",
  80.      *     "partner.joined.projects.assigned.team.leaders",
  81.      *     "partner.manage.base.team.lead",
  82.      *     "partner.smart.active.employees",
  83.      *     "timesheet.for.stakeholder",
  84.      *     "timesheet.for.partner",
  85.      *     "partner.selected.project",
  86.      * 
  87.      *     "project.details.orders",
  88.      *     "order.detail",
  89.      *     "order.lead",
  90.      *
  91.      *     "timesheet.collected.base",
  92.      *
  93.      *     "worker.base",
  94.      *     "worker.core",
  95.      *
  96.      *     "worker.substitution.core",
  97.      *
  98.      *     "worker@ref",
  99.      *     "worker@core",
  100.      *     "worker@base"
  101.      *
  102.      * })
  103.      */
  104.     private $name;
  105.     /**
  106.      * @ORM\Column(type="string", length=255)
  107.      * @Groups({"worker.manage.base",
  108.      *     "partner.joined.projects.assigned.team.leaders",
  109.      *     "partner.manage.base.team.lead",
  110.      *     "partner.smart.active.employees",
  111.      *     "timesheet.for.stakeholder",
  112.      *     "timesheet.for.partner",
  113.      *     "partner.selected.project",
  114.      * 
  115.      *     "project.details.orders",
  116.      *     "order.detail",
  117.      * 
  118.      *     "order.lead",
  119.      *
  120.      *     "timesheet.collected.base",
  121.      *
  122.      *     "worker.base",
  123.      *     "worker.core",
  124.      *
  125.      *     "worker.substitution.core",
  126.      *
  127.      *     "worker@ref",
  128.      *     "worker@core",
  129.      *     "worker@base"
  130.      * })
  131.      */
  132.     private $surname;
  133.     /**
  134.      * Update over Subscriber 🔥
  135.      * @Groups({
  136.      *     "partner.joined.projects.assigned.team.leaders",
  137.      *     "partner.manage.base.team.lead",
  138.      *     "partner.smart.active.employees",
  139.      *     "worker.manage.base",
  140.      *     "partner.selected.project",
  141.      *
  142.      *     "project.details.orders",
  143.      *     "order.detail",
  144.      *     "order.lead",
  145.      *     "worker.substitution.core",
  146.      *
  147.      *     "worker.core",
  148.      *
  149.      *     "worker@core",
  150.      *     "worker@base"
  151.      * })
  152.      */
  153.     private $full_name;
  154.     /**
  155.      * @deprecated use in WorkerActivities
  156.      * @ORM\Column(type="date_immutable", nullable=true)
  157.      */
  158.     private $entry_at;
  159.     /**
  160.      * @deprecated use in WorkerActivities
  161.      * @ORM\Column(type="date_immutable", nullable=true)
  162.      */
  163.     private $exit_at;
  164.     /**
  165.      * @ORM\Column(type="date_immutable", nullable=true)
  166.      * @Groups({
  167.      *     "worker.manage.base",
  168.      *     "worker.core",
  169.      *
  170.      *     "worker@core"
  171.      * })
  172.      */
  173.     private $birthday_at;
  174.     /**
  175.      * @ORM\Column(type="string", length=255)
  176.      * @Gedmo\Slug(fields={"name", "surname"})
  177.      * @Groups({
  178.      *     "worker.manage.base",
  179.      *     "partner.smart.active.employees",
  180.      *     "worker.core",
  181.      *
  182.      *     "worker@core",
  183.      *     "worker@base"
  184.      * })
  185.      */
  186.     private $slug;
  187.     /**
  188.      * @ORM\ManyToMany(targetEntity=Qualification::class, inversedBy="workers", fetch="EXTRA_LAZY")
  189.      * @Groups({
  190.      *     "worker.manage.base",
  191.      *
  192.      *     "worker@qualifications"
  193.      * })
  194.      * @ORM\JoinColumn(onDelete="CASCADE")
  195.      */
  196.     private $qualifications;
  197.     /**
  198.      * PRIMARY (varsayilan) nitelik — SAAT UCRETI onerisinin dayanagi.
  199.      *
  200.      * Kullanici karari 2026-09-29: isci aktiviteye kaydedilirken secilir; `qualifications`
  201.      * koleksiyonundaki DIGER nitelikler ucrete ETKI ETMEZ. NULL = secilmemis → oneri uretilmez.
  202.      *
  203.      * 🪤 Bayrak (`worker_qualification.is_default`) yerine FK: FK tekilligi YAPISAL garanti eder,
  204.      *    bayrakta iki satirin birden isaretlenmesi engellenemezdi.
  205.      * 🪤 Secilen nitelik `qualifications` icinde de olmali — aksi halde "sahip olmadigi meslekten
  206.      *    ucret onerilir". Dogrulama kayit tarafinda (`WorkerService`).
  207.      *
  208.      * @ORM\ManyToOne(targetEntity=Qualification::class)
  209.      * @ORM\JoinColumn(name="default_qualification_id", nullable=true, onDelete="SET NULL")
  210.      * @Groups({
  211.      *     "worker.manage.base",
  212.      *
  213.      *     "worker@qualifications",
  214.      *     "worker@core"
  215.      * })
  216.      */
  217.     private $default_qualification;
  218.     /**
  219.      * ❌❌❌❌❌ TODO Bu kisim table halen colon cikarilmasi lazim
  220.      * @deprecated use in WorkerActivities
  221.      * ORM\OneToMany(targetEntity=WorkerInProject::class, mappedBy="worker", orphanRemoval=true, fetch="EXTRA_LAZY")
  222.      * @ORM\OrderBy({"id":"DESC"})
  223.      */
  224.     private $worker_in_projects;
  225.     /**
  226.      * @ORM\OneToMany(targetEntity=WorkerActivities::class, mappedBy="worker", cascade={"persist", "remove"}, orphanRemoval=true, fetch="EXTRA_LAZY" )
  227.      * @ORM\OrderBy({"id":"DESC"})
  228.      * @Groups({
  229.      *     "worker.manage.base",
  230.      *     "worker.actually.activity",
  231.      *     "worker.activities",
  232.      *
  233.      *     "worker@activities"
  234.      *
  235.      * })
  236.      *
  237.      */
  238.     private $worker_activities;
  239.     /**
  240.      * @deprecated use latest_activity
  241.      * Groups({"worker.actually.activity"})
  242.      */
  243.     private $worker_actually_activity;
  244.     /**
  245.      * @ORM\OneToMany(targetEntity=WorkerCertificates::class, mappedBy="worker", cascade={"persist", "remove"}, orphanRemoval=true, fetch="EXTRA_LAZY" )
  246.      * @Groups({
  247.      *     "worker.manage.base",
  248.      *
  249.      *     "worker@certificates"
  250.      * })
  251.      */
  252.     private $worker_certificates;
  253.     /**
  254.      * @deprecated use inside WorkerActivities
  255.      * ORM\OneToMany(targetEntity=WorkerTimesheet::class, mappedBy="worker_a", cascade={"persist"}, cascade={"persist", "remove"}, orphanRemoval=true, fetch="EXTRA_LAZY")
  256.      */
  257.     private $worker_timesheets;
  258.     /**
  259.      * ⚠️ TODO Bu alan ismi deprecated
  260.      * @deprecated this is worker_activity daily_working_hours
  261.      *  Bu alan Isciye ozel onun default calisma saati ama her Activity icin farkil olabilir
  262.      * @ORM\Column(type="decimal", precision=4, scale=2, nullable=true)
  263.      * @Groups({
  264.      *     "worker.manage.base",
  265.      *
  266.      *     "worker@core"
  267.      * })
  268.      */
  269.     private $daily_work_time;
  270.     /**
  271.      *  ⚠️ TODO Bu alan ismi deprecated
  272.      * @deprecated this is worker_activity hourly_rate
  273.      * Bu alan Isciye ozel onun default calisma ucreti ama her Activity icin farkil olabilir, ayrica her proje icinde
  274.      * @ORM\Column(type="decimal", precision=7, scale=2, nullable=true)
  275.      * @Groups({
  276.      *     "worker.manage.base",
  277.      *     "worker.manage.selected.worker.in.project",
  278.      *     "worker.manage.joined.projects",
  279.      *
  280.      *     "worker@core"
  281.      * })
  282.      */
  283.     private $cost_per_hour;
  284.     /**
  285.      * @ORM\Column(type="string", length=64, nullable=true, unique=false )
  286.      * @Groups({
  287.      *     "worker.manage.base",
  288.      *
  289.      *     "worker@core"
  290.      * })
  291.      */
  292.     private $personal_id;
  293.     // Additional param
  294.     private array $total_worked_time;
  295.     /**
  296.      * @ORM\Column(type="datetime_immutable", nullable=true)
  297.      * @Groups({
  298.      *      "worker@core"
  299.      *  })
  300.      */
  301.     private $created_at;
  302.     /**
  303.      * @ORM\Column(type="string", length=24 , nullable=true )
  304.      * @Groups({
  305.      *     "worker.manage.base",
  306.      *
  307.      *     "worker@core"
  308.      * })
  309.      */
  310.     private $phone_number;
  311.     /**
  312.      * Sozialversicherungsnummer — KİMLİK ANAHTARI (karar verdim 2026-09-17): kayıt bu numaraya
  313.      * göre yapılır; zorunlu ve tekil (unique_social_insurance_number). Normalize saklanır: büyük harf,
  314.      * boşluksuz (setter). DB'de nullable — eski satırlar boş; her upsert'te zorunlu olduğu için zamanla
  315.      * dolar, unique index NULL'ları ayrı sayar. (ad, soyad, doğum günü) anahtarı ikincil uyarı olarak kalır.
  316.      * @ORM\Column(type="string", length=32, nullable=true)
  317.      * @Groups({
  318.      *     "worker.manage.base",
  319.      *     "worker.core",
  320.      *
  321.      *     "worker@core"
  322.      * })
  323.      */
  324.     private $social_insurance_number;
  325.     /**
  326.      * @ORM\Column(type="string", length=255, nullable=true)
  327.      * @Groups({
  328.      *     "worker.manage.base",
  329.      *
  330.      *     "worker@core"
  331.      * })
  332.      */
  333.     private $uiid;
  334.     /**
  335.      * MUTATE THIS
  336.      * @ORM\Column(type="string", length=255, nullable=true)
  337.      * @Groups({
  338.      *     "worker.manage.base",
  339.      *     "partner.smart.active.employees",
  340.      *
  341.      *     "worker@core",
  342.      *     "worker@base"
  343.      * })
  344.      */
  345.     private $profile_image;
  346.     /**
  347.      * ____________________________________________________________________________________________________
  348.      * @deprecated use Original Filed And Mutate is over Subscriber
  349.      *
  350.      * Event Listener Prop
  351.      * This prop Update during event.listener
  352.      * @Groups({
  353.      *     "worker.manage.base",
  354.      *     "partner.smart.active.employees",
  355.      *
  356.      *     "worker@core"
  357.      * })
  358.      */
  359.     private $profile_image_full_path;
  360.     /**
  361.      * @deprecated use Original Filed And Mutate is over Subscriber use profile_image instead
  362.      * TODO bu ozellik EventListernes yada Subscriber uzerinden yapilacak
  363.      * Event Listener Prop
  364.      * This prop Update during event.listener
  365.      * @param string $profile_image_full_path
  366.      * @return Worker|null
  367.      */
  368.     public function setProfileImageFullPath( string $profile_image_full_path ): ?self {
  369.         $this->profile_image_full_path = $profile_image_full_path;//  $this->getServiceArgumentFileDirs()['fetch'] . DIRECTORY_SEPARATOR . $this->getProfileImage();
  370.         return $this;
  371.     }
  372.     /**
  373.      * @deprecated use Original Filed And Mutate is over Subscriber use profile_image instead
  374.      * Event Listener Prop
  375.      */
  376.     public function getProfileImageFullPath(): ?string { return $this->profile_image_full_path; /* $this->getServiceArgumentFileDirs()['fetch'] . DIRECTORY_SEPARATOR . $this->getProfileImage(); */ }
  377.     //  ____________________________________________________________________________________________________
  378.     /**
  379.      * TODO here 🔥worker activity uzerinden degil !!!
  380.      * @ORM\OneToMany(targetEntity=UserAppSettings::class, mappedBy="worker")
  381.      * @Groups({
  382.      *     "worker@user_app_settings"
  383.      *  })
  384.      */
  385.     private $user_app_settings;
  386.     /**
  387.      * @deprecated use in worker activity
  388.      * @ORM\ManyToMany(targetEntity=AccessRoles::class, inversedBy="workers")
  389.      */
  390.     private $worker_accessed_roles;
  391.     /**
  392.      * TODO islemler bittikten sonra cikar
  393.      * TODO this should be in WorkerActivities
  394.      * @ORM\OneToMany(targetEntity=ProjectOrders::class, mappedBy="order_lead")
  395.      */
  396.     private $projectOrders;
  397.     /**
  398.      * TODO thisi deprecated !!!!
  399.      * @deprecated use inside WorkerActivities
  400.      * @ORM\OneToOne(targetEntity=User::class, inversedBy="worker", cascade={"persist", "remove"})
  401.      * @Groups({
  402.      *     "worker.user",
  403.      * })
  404.      */
  405.     private $user;
  406.     /**
  407.      * ⚠️ Update over Subscriber
  408.      * @Groups({
  409.      *     "worker.latest.activity",
  410.      *     "worker@latest_activity"
  411.      * })
  412.     */
  413.     private $latest_activity;
  414.     /**
  415.      * @ORM\Column(type="string", length=255, nullable=true)
  416.      * @Groups({
  417.      *       "worker@base",
  418.      *       "worker@core"
  419.      * })
  420.      */
  421.     private $email;
  422.     /**
  423.      * @param mixed $latest_activity
  424.      */
  425.     public function setLatestActivity(?WorkerActivities $latest_activity): self
  426.     {
  427.         $this->latest_activity = $latest_activity;
  428.         return $this;
  429.     }
  430.     public function getLatestActivity(): ?WorkerActivities
  431.     {
  432.         return $this->latest_activity;
  433.     }
  434.     /**
  435.      * @return mixed
  436.      */
  437.     public function getTotalWorkedTime(): array
  438.     {
  439.         return $this->total_worked_time;
  440.     }
  441.     /**
  442.      * @param mixed $total_worked_time
  443.      */
  444.     public function setTotalWorkedTime( \DateInterval $total_worked_time ): void
  445.     {
  446.         $this->total_worked_time = [
  447.             "days" => $total_worked_time->days,
  448.             "month" => $total_worked_time->m,
  449.             "year" => $total_worked_time->y,
  450.         ];
  451.     }
  452.     /**
  453.      * @return mixed
  454.      */
  455.     public function getFullName()
  456.     {
  457.         return $this->full_name ?? $this->name . " " . $this->surname;
  458.     }
  459.     /**
  460.      * @param mixed $full_name
  461.      */
  462.     public function setFullName($full_name): self
  463.     {
  464.         $this->full_name = $full_name;
  465.         return $this;
  466.     }
  467.     public function __construct()
  468.     {
  469.         $this->qualifications = new ArrayCollection();
  470.         $this->projects = new ArrayCollection();
  471.         $this->worker_in_projects = new ArrayCollection();
  472.         $this->worker_activities = new ArrayCollection();
  473.         $this->worker_certificates = new ArrayCollection();
  474.         $this->worker_timesheets = new ArrayCollection();
  475.         $this->user_app_settings = new ArrayCollection();
  476.         $this->role = new ArrayCollection();
  477.         $this->worker_accessed_roles = new ArrayCollection();
  478.         // TODO this should be in WorkerActivities
  479.         $this->projectOrders = new ArrayCollection();
  480.         // $this->ordersWithDelegatedAccess = new ArrayCollection();
  481.     }
  482.     public function getId(): ?int
  483.     {
  484.         return $this->id;
  485.     }
  486.     public function getName(): ?string
  487.     {
  488.         return $this->name;
  489.     }
  490.     public function setName(string $name): self
  491.     {
  492.         $this->name = $name;
  493.         return $this;
  494.     }
  495.     public function getSurname(): ?string
  496.     {
  497.         return $this->surname;
  498.     }
  499.     public function setSurname(string $surname): self
  500.     {
  501.         $this->surname = $surname;
  502.         return $this;
  503.     }
  504.     public function getEntryAt(): ?\DateTimeImmutable
  505.     {
  506.         return $this->entry_at;
  507.     }
  508.     public function setEntryAt(?\DateTimeImmutable $entry_at): self
  509.     {
  510.         $this->entry_at = $entry_at;
  511.         return $this;
  512.     }
  513.     public function getExitAt(): ?\DateTimeImmutable
  514.     {
  515.         return $this->exit_at;
  516.     }
  517.     public function setExitAt(?\DateTimeImmutable $exit_at): self
  518.     {
  519.         $this->exit_at = $exit_at;
  520.         return $this;
  521.     }
  522.     public function getBirthdayAt(): ?\DateTimeImmutable
  523.     {
  524.         return $this->birthday_at;
  525.         // return (new \DateTimeImmutable($this->birthday_at))->format('d.m.Y');
  526.     }
  527.     // Gün hassasiyeti kolon TİPİNDEN gelir (`date_immutable` → DB `DATE`): DBAL yazarken/okurken
  528.     // ve UniqueEntity sorgusunda saati düşürür. Neden: tekillik (name, surname, birthday_at) bu
  529.     // kolona bağlı; eski `datetime` kolonda V1 formunun yazdığı saat unique index'i kör ediyordu
  530.     // (prod vakası W-2, bkz. Frontend/src/app/modules/EmployeeV2/TODO.md). Setter'da ayrıca
  531.     // setTime(0,0,0) YAPILMAZ — tek doğruluk kaynağı tip. (Satır yorumu bilinçli: docblock'ta
  532.     // "@Unique..." yazınca annotation reader patlıyor.)
  533.     public function setBirthdayAt(?\DateTimeImmutable $birthday_at): self
  534.     {
  535.         $this->birthday_at = $birthday_at;
  536.         return $this;
  537.     }
  538.     public function getSlug(): ?string
  539.     {
  540.         return $this->slug;
  541.     }
  542.     public function setSlug(string $slug): self
  543.     {
  544.         $this->slug = $slug;
  545.         return $this;
  546.     }
  547.     /**
  548.      * @return Collection<int, Qualification>
  549.      */
  550.     public function getQualifications(): ?Collection
  551.     {
  552.             return $this->qualifications;
  553.     }
  554.     public function addQualification(Qualification $qualification): self
  555.     {
  556.         if (!$this->qualifications->contains($qualification)) {
  557.             $this->qualifications[] = $qualification;
  558.         }
  559.         return $this;
  560.     }
  561.     public function removeQualification(Qualification $qualification): self
  562.     {
  563.         $this->qualifications->removeElement($qualification);
  564.         return $this;
  565.     }
  566.     /**
  567.      * @return Collection<int, WorkerInProject>
  568.      */
  569.     public function getWorkerInProjects(): ?Collection
  570.     {
  571.         return $this->worker_in_projects;
  572.     }
  573.     public function addWorkerInProject(WorkerInProject $workerInProject): self
  574.     {
  575.         if (!$this->worker_in_projects->contains($workerInProject)) {
  576.             $this->worker_in_projects[] = $workerInProject;
  577.             $workerInProject->setWorker($this);
  578.         }
  579.         return $this;
  580.     }
  581.     public function removeWorkerInProject(WorkerInProject $workerInProject): self
  582.     {
  583.         if ($this->worker_in_projects->removeElement($workerInProject)) {
  584.             // set the owning side to null (unless already changed)
  585.             if ($workerInProject->getWorker() === $this) {
  586.                 $workerInProject->setWorker(null);
  587.             }
  588.         }
  589.         return $this;
  590.     }
  591.     /**
  592.      * @return Collection<int, WorkerActivities>
  593.      */
  594.     public function getWorkerActivities(): Collection
  595.     {
  596.         return $this->worker_activities;
  597.     }
  598.     /**
  599.      * @deprecated use worker_actually_activity
  600.      * @return Collection<int, WorkerActivities>
  601.      */
  602.     public function getWorkerActuallyPartner(): ?Partner
  603.     {
  604.         #dd($this->getWorkerActuallyActivity()['entity']->getPartner());
  605.         return $this->getWorkerActuallyActivity() ? $this->getWorkerActuallyActivity()['entity']->getPartner() : null;
  606.     }
  607.     /**
  608.      * ¨@deprecated use latest_activity
  609.     */
  610.     public function setWorkerActuallyActivity( WorkerActivities $workerActivity ): void
  611.     {
  612.         $this->worker_actually_activity = $workerActivity;
  613.     }
  614.     /**
  615.      * ¨@deprecated use latest_activity
  616.      */
  617.     public function getWorkerActuallyActivity()
  618.     {
  619.        // return $this->worker_actually_activity;
  620. //        $arr = $this->getWorkerActivities()->filter( function ( /**@var $workerActivity WorkerActivities*/ $workerActivity ){
  621. //            return is_null($workerActivity->getExitAt());
  622. //        })->toArray();
  623.         $simplified = $this->getWorkerActivities()->map( function ( /**@var $workerActivity WorkerActivities*/ $workerActivity ){
  624.             return [
  625.                 "id" => $workerActivity->getId(),
  626.                 "entry_at" => $workerActivity->getEntryAt(),
  627.                 "exit_at" => $workerActivity->getExitAt(),
  628.                 "created_at" => $workerActivity->getCreatedAt(),
  629.                 "entity" => $workerActivity
  630.             ];
  631.         })->toArray();
  632.         usort($simplified, fn($a, $b) => $b['created_at'] <=> $a['created_at']); // ID'ye göre azalan sıralama
  633.         return $simplified[0] ?? null; // ID'si en büyük olan
  634.     }
  635.     public function addWorkerActivity(WorkerActivities $workerActivity): self
  636.     {
  637.         if (!$this->worker_activities->contains($workerActivity)) {
  638.             $this->worker_activities[] = $workerActivity;
  639.             $workerActivity->setWorker($this);
  640.         }
  641.         return $this;
  642.     }
  643.     public function removeWorkerActivity(WorkerActivities $workerActivity): self
  644.     {
  645.         if ($this->worker_activities->removeElement($workerActivity)) {
  646.             // set the owning side to null (unless already changed)
  647.             if ($workerActivity->getWorker() === $this) {
  648.                 $workerActivity->setWorker(null);
  649.             }
  650.         }
  651.         return $this;
  652.     }
  653.     /**
  654.      * @return Collection<int, WorkerCertificates>
  655.      */
  656.     public function getWorkerCertificates(): Collection
  657.     {
  658.         return $this->worker_certificates;
  659.     }
  660.     public function addWorkerCertificate(WorkerCertificates $workerCertificate): self
  661.     {
  662.         if (!$this->worker_certificates->contains($workerCertificate)) {
  663.             $this->worker_certificates[] = $workerCertificate;
  664.             $workerCertificate->setWorker($this);
  665.         }
  666.         return $this;
  667.     }
  668.     public function removeWorkerCertificate(WorkerCertificates $workerCertificate): self
  669.     {
  670.         if ($this->worker_certificates->removeElement($workerCertificate)) {
  671.             // set the owning side to null (unless already changed)
  672.             if ($workerCertificate->getWorker() === $this) {
  673.                 $workerCertificate->setWorker(null);
  674.             }
  675.         }
  676.         return $this;
  677.     }
  678.     /**
  679.      * @return Collection<int, WorkerTimesheet>
  680.      */
  681.     public function getWorkerTimesheets(): ?Collection
  682.     {
  683.         return $this->worker_timesheets;
  684.     }
  685.     public function addWorkerTimesheet(WorkerTimesheet $workerTimesheet): self
  686.     {
  687.         if (!$this->worker_timesheets->contains($workerTimesheet)) {
  688.             $this->worker_timesheets[] = $workerTimesheet;
  689.             $workerTimesheet->setWorker($this);
  690.         }
  691.         return $this;
  692.     }
  693.     public function removeWorkerTimesheet(WorkerTimesheet $workerTimesheet): self
  694.     {
  695.         if ($this->worker_timesheets->removeElement($workerTimesheet)) {
  696.             // set the owning side to null (unless already changed)
  697.             if ($workerTimesheet->getWorker() === $this) {
  698.                 $workerTimesheet->setWorker(null);
  699.             }
  700.         }
  701.         return $this;
  702.     }
  703.     public function getCostPerHour(): ?float
  704.     {
  705.         return $this->cost_per_hour;
  706.     }
  707.     public function setCostPerHour(?float $cost_per_hour): self
  708.     {
  709.         $this->cost_per_hour = $cost_per_hour;
  710.         return $this;
  711.     }
  712.     public function getDailyWorkTime(): ?float
  713.     {
  714.         return $this->daily_work_time;
  715.     }
  716.     public function setDailyWorkTime(?float $daily_work_time): self
  717.     {
  718.         $this->daily_work_time = $daily_work_time;
  719.         return $this;
  720.     }
  721.     public function getPersonalId(): ?string
  722.     {
  723.         return $this->personal_id;
  724.     }
  725.     public function setPersonalId(?string $personal_id): self
  726.     {
  727.         $this->personal_id = $personal_id;
  728.         return $this;
  729.     }
  730.     public function getCreatedAt(): ?\DateTimeImmutable
  731.     {
  732.         return $this->created_at;
  733.     }
  734.     public function setCreatedAt(\DateTimeImmutable $created_at): self
  735.     {
  736.         $this->created_at = $created_at;
  737.         return $this;
  738.     }
  739.     public function getPhoneNumber(): ?string
  740.     {
  741.         return $this->phone_number;
  742.     }
  743.     public function getSocialInsuranceNumber(): ?string
  744.     {
  745.         return $this->social_insurance_number;
  746.     }
  747.     /** Normalize: büyük harf + tüm boşluklar atılır; boş → NULL (unique index için). */
  748.     public function setSocialInsuranceNumber(?string $social_insurance_number): self
  749.     {
  750.         $normalized = $social_insurance_number === null ? '' : strtoupper(preg_replace('/\s+/', '', $social_insurance_number));
  751.         $this->social_insurance_number = $normalized === '' ? null : $normalized;
  752.         return $this;
  753.     }
  754.     public function setPhoneNumber(?string $phone_number): self
  755.     {
  756.         $this->phone_number = $phone_number;
  757.         return $this;
  758.     }
  759.     public function getUiid(): ?string
  760.     {
  761.         return $this->uiid;
  762.     }
  763.     public function setUiid(?string $uiid): self
  764.     {
  765.         $this->uiid = $uiid;
  766.         return $this;
  767.     }
  768.     public function getProfileImage(): ?string
  769.     {
  770.         return $this->profile_image;
  771.     }
  772.     public function setProfileImage(?string $profile_image): self
  773.     {
  774.         $this->profile_image = $profile_image;
  775.         return $this;
  776.     }
  777.     /**
  778.      * @return Collection<int, UserAppSettings>
  779.      */
  780.     public function getUserAppSettings(): Collection
  781.     {
  782.         return $this->user_app_settings;
  783.     }
  784.     public function addUserAppSetting(UserAppSettings $userAppSetting): self
  785.     {
  786.         if (!$this->user_app_settings->contains($userAppSetting)) {
  787.             $this->user_app_settings[] = $userAppSetting;
  788.             $userAppSetting->setWorker($this);
  789.         }
  790.         return $this;
  791.     }
  792.     public function removeUserAppSetting(UserAppSettings $userAppSetting): self
  793.     {
  794.         if ($this->user_app_settings->removeElement($userAppSetting)) {
  795.             // set the owning side to null (unless already changed)
  796.             if ($userAppSetting->getWorker() === $this) {
  797.                 $userAppSetting->setWorker(null);
  798.             }
  799.         }
  800.         return $this;
  801.     }
  802.     /**
  803.      * @return Collection<int, AccessRoles>
  804.      */
  805.     public function getWorkerAccessedRoles(): Collection
  806.     {
  807.         return $this->worker_accessed_roles;
  808.     }
  809.     public function addWorkerAccessedRole(AccessRoles $workerAccessedRole): self
  810.     {
  811.         if (!$this->worker_accessed_roles->contains($workerAccessedRole)) {
  812.             $this->worker_accessed_roles[] = $workerAccessedRole;
  813.         }
  814.         return $this;
  815.     }
  816.     public function removeWorkerAccessedRole(AccessRoles $workerAccessedRole): self
  817.     {
  818.         $this->worker_accessed_roles->removeElement($workerAccessedRole);
  819.         return $this;
  820.     }
  821.     /**
  822.      * // TODO this should be in WorkerActivities
  823.      * @return Collection<int, ProjectOrders>
  824.      */
  825.     public function getProjectOrders(): Collection
  826.     {
  827.         return $this->projectOrders;
  828.     }
  829.     // TODO this should be in WorkerActivities
  830.     public function addProjectOrder(ProjectOrders $projectOrder): self
  831.     {
  832.         if (!$this->projectOrders->contains($projectOrder)) {
  833.             $this->projectOrders[] = $projectOrder;
  834.             $projectOrder->setOrderLead($this);
  835.         }
  836.         return $this;
  837.     }
  838.     // TODO this should be in WorkerActivities
  839.     public function removeProjectOrder(ProjectOrders $projectOrder): self
  840.     {
  841.         if ($this->projectOrders->removeElement($projectOrder)) {
  842.             // set the owning side to null (unless already changed)
  843.             if ($projectOrder->getOrderLead() === $this) {
  844.                 $projectOrder->setOrderLead(null);
  845.             }
  846.         }
  847.         return $this;
  848.     }
  849.     public function getUser(): ?User
  850.     {
  851.         return $this->user;
  852.     }
  853.     public function setUser(?User $user): self
  854.     {
  855.         $this->user = $user;
  856.         return $this;
  857.     }
  858.     public function getEmail(): ?string
  859.     {
  860.         return $this->email;
  861.     }
  862.     public function setEmail(?string $email): self
  863.     {
  864.         $this->email = $email;
  865.         return $this;
  866.     }
  867.     public function getDefaultQualification(): ?Qualification
  868.     {
  869.         return $this->default_qualification;
  870.     }
  871.     public function setDefaultQualification(?Qualification $default_qualification): self
  872.     {
  873.         $this->default_qualification = $default_qualification;
  874.         return $this;
  875.     }
  876. }