src/Entity/Project/Project.php line 95

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace App\Entity\Project;
  3. use ApiPlatform\Core\Annotation\ApiFilter;
  4. use ApiPlatform\Core\Annotation\ApiProperty;
  5. use ApiPlatform\Core\Annotation\ApiResource;
  6. use ApiPlatform\Core\Annotation\ApiSubresource;
  7. use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\BooleanFilter;
  8. use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
  9. use App\Controller\RemoveDeveloperFromProjectController;
  10. use App\Controller\RemoveManagerFromProjectController;
  11. use App\Dto\{ProjectInput,
  12.     ProjectOutput,
  13.     TimeEntryFixInput,
  14.     TimeEntryFixOutput};
  15. use App\Entity\Contractor;
  16. use App\Entity\Plan\Month;
  17. use App\Entity\Plan\WeekPlan as Plan;
  18. use App\Entity\TimeControl\Task;
  19. use App\Entity\TimeControl\TimeEntry;
  20. use App\Entity\Unit;
  21. use App\Entity\User;
  22. use App\Interfaces\SluggableInterface;
  23. use App\Interfaces\UuidKeyInterface;
  24. use App\Traits\SlugAsIdTrait;
  25. use App\Traits\TimestampableEntity;
  26. use Doctrine\Common\Collections\ArrayCollection;
  27. use Doctrine\Common\Collections\Collection;
  28. use Doctrine\ORM\Mapping as ORM;
  29. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  30. use Symfony\Component\Serializer\Annotation\Groups;
  31. use Symfony\Component\Validator\Constraints as Assert;
  32. #[ApiResource(
  33.     collectionOperations: [
  34.         'get',
  35.         'post' => ['security' => "is_granted('ROLE_MASTER_MANAGER')"],
  36.     ],
  37.     itemOperations: [
  38.         'get',
  39.         'put' => ['security' => "is_granted('PROJECT_EDIT', object)"],
  40.         'patch' => ['security' => "is_granted('PROJECT_EDIT', object)"],
  41.         'delete' => [
  42.             'security' => "is_granted('PROJECT_EDIT', object)",
  43.             'method' => 'DELETE',
  44.         ],
  45.         'remove-manager' => [
  46.             'security' => "is_granted('PROJECT_EDIT', object)",
  47.             'method' => 'DELETE',
  48.             'path' => '/projects/{slug}/managers/{id}',
  49.             'controller' => RemoveManagerFromProjectController::class,
  50.             'openapi_context' => [
  51.                 'summary' => 'Remove manager from project',
  52.                 'description' => 'Remove manager from project',
  53.                 'parameters' => [['in' => 'path''name' => 'slug''required' => true], ['in' => 'path''name' => 'id''required' => true]],
  54.             ],
  55.         ],
  56.         'remove-developer' => [
  57.             'security' => "is_granted('PROJECT_EDIT', object)",
  58.             'method' => 'DELETE',
  59.             'path' => '/projects/{slug}/developers/{id}',
  60.             'controller' => RemoveDeveloperFromProjectController::class,
  61.             'openapi_context' => [
  62.                 'summary' => 'Remove developer from project''description' => 'Remove developer from project',
  63.                 'parameters' => [['in' => 'path''name' => 'slug''required' => true], ['in' => 'path''name' => 'id''required' => true]],
  64.             ],
  65.         ],
  66.         Project::PATCH_TE_OPERATION => [
  67.             'method' => 'PATCH',
  68.             'path' => 'projects/{slug}/time-entries',
  69.             'input' => TimeEntryFixInput::class,
  70.             'output' => TimeEntryFixOutput::class,
  71.             'security' => "is_granted('ROLE_PROJECT_FIXER')",
  72.             'openapi_context' => ['summary' => 'Set fix $ approved for time-entries'],
  73.         ],
  74.     ],
  75.     attributes: [
  76.         'order' => ['title' => 'ASC'],
  77.     ],
  78.     inputProjectInput::class,
  79.     outputProjectOutput::class,
  80. )]
  81. #[ApiFilter(SearchFilter::class, properties: ['managers.id' => 'exact'])]
  82. #[ApiFilter(SearchFilter::class, properties: [
  83.     'title' => 'i' SearchFilter::STRATEGY_PARTIAL,
  84.     'description' => 'i' SearchFilter::STRATEGY_PARTIAL,
  85. ])]
  86. #[ApiFilter(BooleanFilter::class, properties: ['archived''isCommercial'])]
  87. #[ORM\Entity(repositoryClass'App\Repository\ProjectRepository')]
  88. #[ORM\Table]
  89. #[ORM\Index(name'idx_project_archived'columns: ['archived'])]
  90. #[ORM\Index(name'idx_project_is_commercial'columns: ['is_commercial'])]
  91. #[UniqueEntity(fields: ['slug'], message'Это Название проекта уже используется')]
  92. class Project implements UuidKeyInterfaceSluggableInterface\Stringable
  93. {
  94.     use SlugAsIdTrait;
  95.     use TimestampableEntity;
  96.     public const READ_GROUP 'Project:read';
  97.     public const PATCH_TE_OPERATION 'patch-te';
  98.     public const TITLE_DESCRIPTION 'Название проекта';
  99.     #[Assert\NotBlank]
  100.     #[Groups([self::READ_GROUP])]
  101.     #[Assert\Length(max255)]
  102.     #[ORM\Column(nullabletrue)]
  103.     private ?string $title null;
  104.     #[Groups([self::READ_GROUP])]
  105.     #[ApiProperty(descriptionself::TITLE_DESCRIPTION)]
  106.     #[ORM\Column(type'text'nullabletrue)]
  107.     private ?string $description null;
  108.     #[Assert\Valid]
  109.     #[Groups([self::READ_GROUP])]
  110.     #[ORM\ManyToOne(targetEntityContractor::class, inversedBy'projects'cascade: ['persist'])]
  111.     #[ORM\JoinColumn(nullablefalse)]
  112.     private ?Contractor $contractor null;
  113.     /**
  114.      * @var Collection<array-key, Manager>
  115.      */
  116.     #[ApiSubresource]
  117.     #[ORM\ManyToMany(targetEntity'App\Entity\Project\Manager'mappedBy'projects')]
  118.     private Collection $managers;
  119.     /**
  120.      * @var Collection<array-key, Developer>
  121.      */
  122.     #[ApiSubresource]
  123.     #[ORM\ManyToMany(targetEntity'App\Entity\Project\Developer'mappedBy'projects')]
  124.     private Collection $developers;
  125.     /**
  126.      * @var Collection<array-key, Stage>
  127.      */
  128.     #[Groups([self::READ_GROUP])]
  129.     #[ApiSubresource]
  130.     #[ORM\OneToMany(targetEntity'App\Entity\Project\Stage'mappedBy'project')]
  131.     private Collection $stages;
  132.     #[Groups([self::READ_GROUP])]
  133.     #[ORM\ManyToOne(targetEntity'App\Entity\Project\Stage')]
  134.     private ?Stage $currentStage null;
  135.     /**
  136.      * @var Collection<array-key, TimeEntry>
  137.      */
  138.     #[ApiSubresource]
  139.     #[ORM\OneToMany(targetEntity'App\Entity\TimeControl\TimeEntry'mappedBy'project')]
  140.     private Collection $timeEntries;
  141.     #[ORM\Column(type'boolean'options: ['default' => false])]
  142.     private bool $archived false;
  143.     /**
  144.      * @var Collection<array-key, DeveloperRate>
  145.      */
  146.     #[ORM\OneToMany(targetEntityDeveloperRate::class, mappedBy'project'cascade: ['persist''remove'])]
  147.     private Collection $rates;
  148.     /**
  149.      * @var Collection<array-key, Plan>
  150.      */
  151.     #[ORM\OneToMany(targetEntityPlan::class, mappedBy'project')]
  152.     private Collection $plans;
  153.     /**
  154.      * @var Collection<array-key, Month>
  155.      */
  156.     #[ORM\OneToMany(targetEntityMonth::class, mappedBy'project')]
  157.     private Collection $months;
  158.     #[ORM\Column(type'date'nullabletrueoptions: ['default' => null])]
  159.     private ?\DateTimeInterface $dateSigning null;
  160.     #[ORM\Column(type'datetime'nullabletrue)]
  161.     private ?\DateTimeInterface $deletedAt null;
  162.     /**
  163.      * @var Collection<int, Task>
  164.      */
  165.     #[ORM\OneToMany(targetEntityTask::class, mappedBy'project')]
  166.     private Collection $tasks;
  167.     #[ORM\Column(type'boolean'options: ['default' => true])]
  168.     private ?bool $isCommercial true;
  169.     #[ORM\ManyToOne(targetEntityUnit::class, inversedBy'projects')]
  170.     private ?Unit $unit null;
  171.     /**
  172.      * Project constructor.
  173.      */
  174.     public function __construct()
  175.     {
  176.         $this->managers = new ArrayCollection();
  177.         $this->developers = new ArrayCollection();
  178.         $this->stages = new ArrayCollection();
  179.         $this->timeEntries = new ArrayCollection();
  180.         $this->rates = new ArrayCollection();
  181.         $this->plans = new ArrayCollection();
  182.         $this->months = new ArrayCollection();
  183.         $this->tasks = new ArrayCollection();
  184.     }
  185.     public function __toString(): string
  186.     {
  187.         return $this->title ?? __CLASS__;
  188.     }
  189.     public function getTitle(): ?string
  190.     {
  191.         return $this->title;
  192.     }
  193.     public function setTitle(?string $title): self
  194.     {
  195.         $this->title $title;
  196.         return $this;
  197.     }
  198.     public function getDescription(): ?string
  199.     {
  200.         return $this->description;
  201.     }
  202.     public function setDescription(?string $description): self
  203.     {
  204.         $this->description $description;
  205.         return $this;
  206.     }
  207.     public function getContractor(): ?Contractor
  208.     {
  209.         return $this->contractor;
  210.     }
  211.     public function setContractor(?Contractor $contractor): self
  212.     {
  213.         $this->contractor $contractor;
  214.         return $this;
  215.     }
  216.     /**
  217.      * @return Collection|Manager[]
  218.      *
  219.      * @psalm-return Collection
  220.      */
  221.     public function getManagers(): Collection
  222.     {
  223.         return $this->managers;
  224.     }
  225.     public function addManager(Manager $manager): self
  226.     {
  227.         if (!$this->managers->contains($manager)) {
  228.             $this->managers[] = $manager;
  229.             $manager->addProject($this);
  230.         }
  231.         return $this;
  232.     }
  233.     public function removeManager(Manager $manager): self
  234.     {
  235.         if ($this->managers->contains($manager)) {
  236.             $this->managers->removeElement($manager);
  237.             $manager->removeProject($this);
  238.         }
  239.         return $this;
  240.     }
  241.     public function getManagerNames(): array
  242.     {
  243.         $data = [];
  244.         foreach ($this->managers as $manager) {
  245.             if (!$manager instanceof Manager || ($user $manager->getUser()) === null) {
  246.                 continue;
  247.             }
  248.             if (!$user instanceof User || ($profile $user->getProfile()) === null) {
  249.                 continue;
  250.             }
  251.             $data[] = $profile->getPerson()->getFullName();
  252.         }
  253.         return $data;
  254.     }
  255.     /**
  256.      * @return Collection<int, Developer>
  257.      */
  258.     public function getDevelopers(): Collection
  259.     {
  260.         return $this->developers;
  261.     }
  262.     public function addDeveloper(Developer $developer): self
  263.     {
  264.         if (!$this->developers->contains($developer)) {
  265.             $this->developers[] = $developer;
  266.             $developer->addProject($this);
  267.         }
  268.         return $this;
  269.     }
  270.     public function removeDeveloper(Developer $developer): self
  271.     {
  272.         if ($this->developers->contains($developer)) {
  273.             $this->developers->removeElement($developer);
  274.             $developer->removeProject($this);
  275.         }
  276.         return $this;
  277.     }
  278.     /**
  279.      * @return Collection|Stage[]
  280.      *
  281.      * @psalm-return Collection
  282.      */
  283.     public function getStages(): Collection
  284.     {
  285.         return $this->stages;
  286.     }
  287.     public function addStage(Stage $stage): self
  288.     {
  289.         if (!$this->stages->contains($stage)) {
  290.             $this->stages[] = $stage;
  291.             $stage->setProject($this);
  292.         }
  293.         return $this;
  294.     }
  295.     public function removeStage(Stage $stage): self
  296.     {
  297.         if ($this->stages->contains($stage)) {
  298.             $this->stages->removeElement($stage);
  299.             // set the owning side to null (unless already changed)
  300.             if ($stage->getProject() === $this) {
  301.                 $stage->setProject(null);
  302.             }
  303.         }
  304.         return $this;
  305.     }
  306.     public function getCurrentStage(): ?Stage
  307.     {
  308.         return $this->currentStage;
  309.     }
  310.     public function setCurrentStage(?Stage $currentStage): self
  311.     {
  312.         $this->currentStage $currentStage;
  313.         return $this;
  314.     }
  315.     /**
  316.      * @psalm-return Collection<int, TimeEntry>
  317.      */
  318.     public function getTimeEntries(): Collection
  319.     {
  320.         return $this->timeEntries;
  321.     }
  322.     public function addTimeEntry(TimeEntry $timeEntry): self
  323.     {
  324.         if (!$this->timeEntries->contains($timeEntry)) {
  325.             $this->timeEntries[] = $timeEntry;
  326.             $timeEntry->setProject($this);
  327.         }
  328.         return $this;
  329.     }
  330.     public function removeTimeEntry(TimeEntry $timeEntry): self
  331.     {
  332.         if ($this->timeEntries->contains($timeEntry)) {
  333.             $this->timeEntries->removeElement($timeEntry);
  334.             // set the owning side to null (unless already changed)
  335.             if ($timeEntry->getProject() === $this) {
  336.                 $timeEntry->setProject(null);
  337.             }
  338.         }
  339.         return $this;
  340.     }
  341.     public function getArchived(): ?bool
  342.     {
  343.         return $this->archived;
  344.     }
  345.     public function setArchived(bool $archived): self
  346.     {
  347.         $this->archived $archived;
  348.         return $this;
  349.     }
  350.     public function getRate(Developer $developer): ?DeveloperRate
  351.     {
  352.         $result $this->rates->map(fn (DeveloperRate $rate) => $rate->getDeveloper() === $developer);
  353.         if (($resultRate $result->first()) instanceof DeveloperRate) {
  354.             return $resultRate;
  355.         }
  356.         return null;
  357.     }
  358.     /**
  359.      * @return Collection<array-key, DeveloperRate>|DeveloperRate[]
  360.      *
  361.      * @psalm-return Collection<array-key, DeveloperRate>
  362.      */
  363.     public function getRates(): Collection
  364.     {
  365.         return $this->rates;
  366.     }
  367.     public function addRate(DeveloperRate $rate): self
  368.     {
  369.         if (!$this->rates->contains($rate)) {
  370.             $this->rates[] = $rate;
  371.             $rate->setProject($this);
  372.         }
  373.         return $this;
  374.     }
  375.     public function removeRate(DeveloperRate $rate): self
  376.     {
  377.         if ($this->rates->removeElement($rate)) {
  378.             if ($rate->getProject() === $this) {
  379.                 $rate->setProject(null);
  380.             }
  381.         }
  382.         return $this;
  383.     }
  384.     /**
  385.      * @return Collection|Plan[]
  386.      *
  387.      * @psalm-return Collection<array-key, Plan>
  388.      */
  389.     public function getPlans(): Collection
  390.     {
  391.         return $this->plans;
  392.     }
  393.     public function addPlan(Plan $plan): self
  394.     {
  395.         if (!$this->plans->contains($plan)) {
  396.             $this->plans[] = $plan;
  397.             $plan->setProject($this);
  398.         }
  399.         return $this;
  400.     }
  401.     public function removePlan(Plan $plan): self
  402.     {
  403.         if ($this->plans->removeElement($plan)) {
  404.             // set the owning side to null (unless already changed)
  405.             if ($plan->getProject() === $this) {
  406.                 $plan->setProject(null);
  407.             }
  408.         }
  409.         return $this;
  410.     }
  411.     /**
  412.      * @return Collection<array-key, Month>|Month[]
  413.      *
  414.      * @psalm-return Collection<array-key, Month>
  415.      */
  416.     public function getMonths(): Collection
  417.     {
  418.         return $this->months;
  419.     }
  420.     public function addMonth(Month $month): self
  421.     {
  422.         if (!$this->months->contains($month)) {
  423.             $this->months[] = $month;
  424.             $month->setProject($this);
  425.         }
  426.         return $this;
  427.     }
  428.     public function removeMonth(Month $month): self
  429.     {
  430.         if ($this->months->removeElement($month)) {
  431.             // set the owning side to null (unless already changed)
  432.             if ($month->getProject() === $this) {
  433.                 $month->setProject(null);
  434.             }
  435.         }
  436.         return $this;
  437.     }
  438.     public function getDateSigning(): ?\DateTimeInterface
  439.     {
  440.         return $this->dateSigning;
  441.     }
  442.     public function setDateSigning(?\DateTimeInterface $dateSigning): self
  443.     {
  444.         $this->dateSigning $dateSigning;
  445.         return $this;
  446.     }
  447.     public function getTasks(): Collection
  448.     {
  449.         return $this->tasks;
  450.     }
  451.     public function addTask(Task $task): self
  452.     {
  453.         if (!$this->tasks->contains($task)) {
  454.             $this->tasks[] = $task;
  455.             $task->setProject($this);
  456.         }
  457.         return $this;
  458.     }
  459.     public function removeTask(Task $task): self
  460.     {
  461.         if ($this->tasks->contains($task)) {
  462.             $this->tasks->removeElement($task);
  463.             $task->setProject(null);
  464.         }
  465.         return $this;
  466.     }
  467.     public function getDeletedAt(): ?\DateTimeInterface
  468.     {
  469.         return $this->deletedAt;
  470.     }
  471.     public function setDeletedAt(?\DateTimeInterface $deletedAt): void
  472.     {
  473.         $this->deletedAt $deletedAt;
  474.     }
  475.     public function getIsCommercial(): ?bool
  476.     {
  477.         return $this->isCommercial;
  478.     }
  479.     public function setIsCommercial(?bool $isCommercial): self
  480.     {
  481.         $this->isCommercial $isCommercial;
  482.         return $this;
  483.     }
  484.     public function getUnit(): ?Unit
  485.     {
  486.         return $this->unit;
  487.     }
  488.     public function setUnit(?Unit $unit): self
  489.     {
  490.         $this->unit $unit;
  491.         return $this;
  492.     }
  493. }