src/Entity/TimeControl/Task.php line 103

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace App\Entity\TimeControl;
  3. use ApiPlatform\Core\Annotation\{ApiFilterApiResourceApiSubresource};
  4. use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\{BooleanFilterDateFilterOrderFilterSearchFilter};
  5. use App\Controller\TasksDownloadController;
  6. use App\Dto\TaskOutput;
  7. use App\Dto\TimeEntryFixInput;
  8. use App\Dto\TimeEntryFixOutput;
  9. use App\Entity\{Project\ProjectUser};
  10. use App\Filter\OrLikeSearchFilter;
  11. use App\Interfaces\UuidKeyInterface;
  12. use App\Repository\TaskRepository;
  13. use App\Traits\UuidEntityTrait;
  14. use Doctrine\Common\Collections\{ArrayCollectionCollection};
  15. use Doctrine\ORM\Mapping as ORM;
  16. use Gedmo\Mapping\Annotation as Gedmo;
  17. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  18. use Symfony\Component\Serializer\Annotation\Groups;
  19. use Symfony\Component\Validator\Constraints as Assert;
  20. #[ApiResource(
  21.     collectionOperations: [
  22.         'get',
  23.         self::FILTERED_OPERATION => [
  24.             'method' => 'GET',
  25.             'output' => TaskOutput::class,
  26.             'path' => '/tasks/filtered',
  27.             'pagination_client_enabled' => true,
  28.         ],
  29.         'post',
  30.         'report' => [
  31.             'method' => 'GET',
  32.             'path' => 'tasks/download',
  33.             'controller' => TasksDownloadController::class,
  34.             'openapi_context' => [
  35.                 'summary' => 'Report by tasks',
  36.                 'description' => 'Download report by tasks',
  37.             ],
  38.         ],
  39.     ],
  40.     itemOperations: [
  41.         'get',
  42.         'put',
  43.         'delete' => [
  44.             'security' => "is_granted('TASK_REMOVE', object)",
  45.             'security_message' => 'Deny delete Task, because exists child fixed TimeEntries',
  46.         ],
  47.         'patch',
  48.         Task::PATCH_TE_OPERATION => [
  49.             'method' => 'PATCH',
  50.             'path' => 'task/{id}/time-entries',
  51.             'input' => TimeEntryFixInput::class,
  52.             'output' => TimeEntryFixOutput::class,
  53.             'security' => "is_granted('ROLE_USER_FIXER')",
  54.             'openapi_context' => ['summary' => 'Set fix $ approved for time-entries'],
  55.         ],
  56.     ],
  57.     attributes: ['order' => ['createdAt' => 'DESC']],
  58. )]
  59. #[ApiFilter(filterClassSearchFilter::class, properties: [
  60.     'user.slug' => SearchFilter::STRATEGY_EXACT,
  61.     'project.slug' => SearchFilter::STRATEGY_EXACT,
  62.     'user.id' => SearchFilter::STRATEGY_EXACT,
  63.     'project.id' => SearchFilter::STRATEGY_EXACT,
  64.     'title' => 'i' SearchFilter::STRATEGY_PARTIAL,
  65.     'description' => 'i' SearchFilter::STRATEGY_PARTIAL,
  66.     'link' => 'i' SearchFilter::STRATEGY_PARTIAL,
  67. ])]
  68. #[ApiFilter(filterClassOrderFilter::class, properties: [
  69.     'createdAt' => [
  70.         'nulls_comparison' => OrderFilter::NULLS_SMALLEST,
  71.         'default_direction' => 'DESC',
  72.     ],
  73.     'user.email' => 'ASC',
  74.     'project.slug' => 'ASC',
  75.     'project.title' => 'ASC',
  76.     'description' => 'ASC',
  77.     'title' => 'ASC',
  78.     'link' => 'ASC',
  79. ])]
  80. #[ApiFilter(filterClassDateFilter::class, properties: [
  81.     'timeEntries.start' => DateFilter::EXCLUDE_NULL,
  82.     'timeEntries.end' => DateFilter::EXCLUDE_NULL,
  83. ])]
  84. #[ApiFilter(filterClassBooleanFilter::class, properties: [
  85.     'favorite',
  86. ])]
  87. #[ApiFilter(OrLikeSearchFilter::class, properties: ['strategy' => 'partial',
  88.     'fields' => [
  89.         'title''description',
  90.     ],
  91. ])]
  92. #[UniqueEntity(
  93.     fields: ['project''title''user'],
  94.     message'Task with same title already exists in project "{{ value }}"',
  95. )]
  96. #[ORM\Entity(repositoryClassTaskRepository::class)]
  97. #[ORM\Table]
  98. #[ORM\Index(name'idx_task_favorite'columns: ['favorite'])]
  99. #[ORM\Index(name'idx_task_is_commercial'columns: ['is_commercial'])]
  100. class Task implements UuidKeyInterface
  101. {
  102.     use UuidEntityTrait;
  103.     public const FILTERED_OPERATION 'filtered';
  104.     public const PATCH_TE_OPERATION 'patch-te';
  105.     #[Groups(['Task:read''Task:write'])]
  106.     #[Assert\NotBlank]
  107.     #[ORM\ManyToOne(targetEntityUser::class, inversedBy'tasks'cascade: ['persist'])]
  108.     private ?User $user null;
  109.     #[Groups(['Task:read''Task:write'])]
  110.     #[Assert\NotBlank]
  111.     #[ORM\ManyToOne(targetEntityProject::class, inversedBy'tasks'cascade: ['persist'])]
  112.     private ?Project $project null;
  113.     /**
  114.      * @var Collection<int, TimeEntry>
  115.      */
  116.     #[Groups(['Task:read''Task:write'])]
  117.     #[ApiSubresource]
  118.     #[ORM\OneToMany(targetEntityTimeEntry::class, mappedBy'task'cascade: ['remove'])]
  119.     private Collection $timeEntries;
  120.     #[Assert\Length(max255)]
  121.     #[Groups(['Task:read''Task:write'])]
  122.     #[ORM\Column(type'text'nullabletrue)]
  123.     private ?string $description null;
  124.     #[Assert\NotBlank]
  125.     #[Assert\Length(max255)]
  126.     #[Groups(['Task:read''Task:write'])]
  127.     #[ORM\Column(type'string'nullabletrue)]
  128.     private ?string $title null;
  129.     #[Assert\Length(max255)]
  130.     #[Groups(['Task:read''Task:write'])]
  131.     #[Assert\Url]
  132.     #[ORM\Column(type'string'nullabletrue)]
  133.     private ?string $link null;
  134.     #[Gedmo\Timestampable(on'create')]
  135.     #[Groups(['Task:read''Task:write'])]
  136.     #[ORM\Column(type'datetime'nullabletrue)]
  137.     private ?\DateTimeInterface $createdAt null;
  138.     #[ORM\Column(type'datetime'nullabletrue)]
  139.     private ?\DateTimeInterface $deletedAt null;
  140.     #[Groups(['Task:read''Task:write'])]
  141.     #[ORM\Column(type'boolean'nullablefalseoptions: ['default' => false])]
  142.     private bool $favorite false;
  143.     #[Groups(['Task:read''Task:write'])]
  144.     #[ORM\Column(type'boolean'nullablefalseoptions: ['default' => true])]
  145.     private bool $isCommercial true;
  146.     public function __construct()
  147.     {
  148.         $this->timeEntries = new ArrayCollection();
  149.     }
  150.     public function setUser(?User $user): self
  151.     {
  152.         $this->user $user;
  153.         return $this;
  154.     }
  155.     public function getUser(): ?User
  156.     {
  157.         return $this->user;
  158.     }
  159.     public function setProject(?Project $project): self
  160.     {
  161.         $this->project $project;
  162.         return $this;
  163.     }
  164.     public function getTimeEntries(): Collection
  165.     {
  166.         return $this->timeEntries;
  167.     }
  168.     public function addTimeEntry(TimeEntry $timeEntry): self
  169.     {
  170.         if (!$this->timeEntries->contains($timeEntry)) {
  171.             $this->timeEntries[] = $timeEntry;
  172.             $timeEntry->setTask($this);
  173.         }
  174.         return $this;
  175.     }
  176.     public function removeTimeEntry(TimeEntry $timeEntry): self
  177.     {
  178.         if ($this->timeEntries->contains($timeEntry)) {
  179.             $this->timeEntries->removeElement($timeEntry);
  180.             $timeEntry->setTask(null);
  181.         }
  182.         return $this;
  183.     }
  184.     public function getProject(): ?Project
  185.     {
  186.         return $this->project;
  187.     }
  188.     public function getDescription(): ?string
  189.     {
  190.         return $this->description;
  191.     }
  192.     public function setDescription(?string $description): self
  193.     {
  194.         $this->description $description;
  195.         return $this;
  196.     }
  197.     public function getTitle(): ?string
  198.     {
  199.         return $this->title;
  200.     }
  201.     public function setTitle(?string $title): self
  202.     {
  203.         $this->title $title;
  204.         return $this;
  205.     }
  206.     public function getLink(): ?string
  207.     {
  208.         return $this->link;
  209.     }
  210.     public function setLink(?string $link): self
  211.     {
  212.         $this->link $link;
  213.         return $this;
  214.     }
  215.     #[Groups(['Task:read''Task:write'])]
  216.     public function getTime(): int
  217.     {
  218.         $result 0;
  219.         foreach ($this->timeEntries as $timeEntry) {
  220.             if (!$timeEntry instanceof TimeEntry) {
  221.                 continue;
  222.             }
  223.             $result += $timeEntry->getLength();
  224.         }
  225.         return $result;
  226.     }
  227.     public function getLimitedTime(\DateTimeInterface $start\DateTimeInterface $end): int
  228.     {
  229.         $result 0;
  230.         $limited $this->timeEntries->filter(static function (TimeEntry $te) use ($start$end) {
  231.             return $te->getStart() >= $start && $te->getEnd() <= $end;
  232.         });
  233.         foreach ($limited as $item) {
  234.             if ($item instanceof TimeEntry) {
  235.                 $result += $item->getLength();
  236.             }
  237.         }
  238.         return $result;
  239.     }
  240.     public function getCreatedAt(): ?\DateTimeInterface
  241.     {
  242.         return $this->createdAt;
  243.     }
  244.     public function setCreatedAt(?\DateTimeInterface $createdAt): self
  245.     {
  246.         $this->createdAt $createdAt;
  247.         return $this;
  248.     }
  249.     public function isFavorite(): bool
  250.     {
  251.         return $this->favorite;
  252.     }
  253.     public function setFavorite(bool $favorite): self
  254.     {
  255.         $this->favorite $favorite;
  256.         return $this;
  257.     }
  258.     public function getDeletedAt(): ?\DateTimeInterface
  259.     {
  260.         return $this->deletedAt;
  261.     }
  262.     public function setDeletedAt(?\DateTimeInterface $deletedAt): void
  263.     {
  264.         $this->deletedAt $deletedAt;
  265.     }
  266.     public function getIsCommercial(): ?bool
  267.     {
  268.         return $this->isCommercial;
  269.     }
  270.     public function setIsCommercial(bool $isCommercial): self
  271.     {
  272.         $this->isCommercial $isCommercial;
  273.         return $this;
  274.     }
  275. }