src/Entity/User.php line 178

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use ApiPlatform\Core\{
  4.     Annotation\ApiFilter,
  5.     Annotation\ApiProperty,
  6.     Annotation\ApiResource,
  7.     Annotation\ApiSubresource,
  8.     Bridge\Doctrine\Common\Filter\SearchFilterInterface,
  9.     Bridge\Doctrine\Orm\Filter\OrderFilter,
  10.     Bridge\Doctrine\Orm\Filter\SearchFilter
  11. };
  12. use App\Doctrine\Filter\ApiArchivesFilter;
  13. use App\Dto\{
  14.     PlanDayFillOutput,
  15.     UserInput,
  16.     UserInputTimeEntry,
  17.     UserInputTimeEntryFix,
  18.     UserMissingOutput,
  19.     UserOutput,
  20.     UserOutputTimeEntryFix,
  21.     UserSetMissingInput,
  22.     UserSetPlanDayInput,
  23.     UserUnsetMissingInput
  24. };
  25. use App\Entity\{
  26.     Embed\Person,
  27.     Plan\PlanDay,
  28.     Project\Developer,
  29.     Project\Manager,
  30.     TimeControl\Task,
  31.     TimeControl\TimeEntry,
  32.     TimeNormalization\Day,
  33.     TimeNormalization\WorkPosition
  34. };
  35. use App\Filter\OrLikeSearchFilter;
  36. use App\Interfaces\{SluggableInterfaceUuidKeyInterface};
  37. use App\Repository\WorkPositionRepository;
  38. use App\Traits\SlugAsIdTrait;
  39. use Doctrine\Common\Collections\{ArrayCollectionCollection};
  40. use Doctrine\ORM\Mapping as ORM;
  41. use Doctrine\ORM\PersistentCollection;
  42. use Gedmo\Mapping\Annotation as Gedmo;
  43. use Symfony\Component\{
  44.     Security\Core\User\PasswordAuthenticatedUserInterface,
  45.     Security\Core\User\UserInterface,
  46.     Validator\Constraints as Assert
  47. };
  48. #[ApiResource(
  49.     collectionOperations: ['get'],
  50.     itemOperations: [
  51.         'get' => [
  52.             'openapi_context' => [
  53.                 'parameters' => [
  54.                     ['name' => 'id''in' => 'path''required' => true'schema' => ['type' => 'string']],
  55.                     ['name' => 'archived''in' => 'query''required' => false'schema' => ['type' => 'boolean']],
  56.                 ],
  57.             ],
  58.             'normalization_context' => [
  59.                 'groups' => ['User:item:read'],
  60.             ],
  61.         ],
  62.         'put' => ['security' => "is_granted('ROLE_ADMIN') or is_granted('ROLE_MASTER_MANAGER') or is_granted('ROLE_HR')"],
  63.         'patch' => ['security' => "is_granted('ROLE_ADMIN') or is_granted('ROLE_MASTER_MANAGER') or is_granted('ROLE_HR')"],
  64.         'delete' => ['security' => "is_granted('ROLE_ADMIN')"],
  65.         User::ITEM_MISSING_PLAN_DAYS => [
  66.             'method' => 'GET',
  67.             'path' => 'users/{slug}/missing',
  68.             'input' => false,
  69.             'output' => UserMissingOutput::class,
  70.             'security' => "is_granted('ROLE_MANAGER')",
  71.             'openapi_context' => [
  72.                 'summary' => 'Get missing period for users',
  73.                 'parameters' => [
  74.                     ['name' => 'periodStart''in' => 'query''required' => true'schema' => ['type' => 'string']],
  75.                     ['name' => 'periodEnd''in' => 'query''required' => true'schema' => ['type' => 'string']],
  76.                 ],
  77.             ],
  78.         ],
  79.         User::PATCH_TE_OPERATION => [
  80.             'method' => 'PATCH',
  81.             'path' => 'users/{slug}/time-entries',
  82.             'input' => UserInputTimeEntry::class,
  83.             'output' => UserOutputTimeEntryFix::class,
  84.             'security' => "is_granted('ROLE_USER_FIXER')",
  85.             'openapi_context' => ['summary' => 'Set fix $ approved for time-entries'],
  86.         ],
  87.         User::ITEM_SET_MISSING_PLAN_DAYS => [
  88.             'method' => 'PATCH',
  89.             'path' => 'users/{slug}/missing/set',
  90.             'input' => UserSetMissingInput::class,
  91.             'output' => false,
  92.             'security' => "is_granted('ROLE_MANAGER')",
  93.             'openapi_context' => ['summary' => 'Set missing period for users'],
  94.         ],
  95.         User::ITEM_UNSET_MISSING_PLAN_DAYS => [
  96.             'method' => 'PATCH',
  97.             'path' => 'users/{slug}/missing/unset',
  98.             'input' => UserUnsetMissingInput::class,
  99.             'output' => false,
  100.             'security' => "is_granted('ROLE_MANAGER')",
  101.             'openapi_context' => ['summary' => 'Delete missing period for users'],
  102.         ],
  103.         User::ITEM_SET_PLAN_DAYS => [
  104.             'method' => 'PATCH',
  105.             'path' => 'users/{slug}/' User::ITEM_SET_PLAN_DAYS,
  106.             'status' => 202,
  107.             'input' => UserSetPlanDayInput::class,
  108.             'output' => PlanDayFillOutput::class,
  109.             'security' => "is_granted('ROLE_MANAGER')",
  110.             'openapi_context' => ['summary' => 'Fill plan days for user in period'],
  111.         ],
  112.         User::ITEM_FIX_TIME_ENTRIES => [
  113.             'method' => 'PATCH',
  114.             'path' => 'users/{slug}/time-entries/fix',
  115.             'input' => UserInputTimeEntryFix::class,
  116.             'output' => UserOutputTimeEntryFix::class,
  117.             'security' => "is_granted('ROLE_USER_FIXER')",
  118.             'openapi_context' => ['summary' => 'Fix TimeEntry allowed to project manager or higher'],
  119.         ],
  120.         User::ITEM_UNFIX_TIME_ENTRIES => [
  121.             'method' => 'PATCH',
  122.             'path' => 'users/{slug}/time-entries/unfix',
  123.             'input' => UserInputTimeEntryFix::class,
  124.             'output' => false,
  125.             'security' => "is_granted('ROLE_USER_FIXER')",
  126.             'openapi_context' => ['summary' => 'Unfix TimeEntry allowed to Main project manager or higher'],
  127.         ],
  128.         User::ITEM_DISMISS => [
  129.             'method' => 'PATCH',
  130.             'path' => 'users/{slug}/dismiss',
  131.             'input' => false,
  132.             'output' => false,
  133.             'security' => "is_granted('ROLE_HR') or is_granted('ROLE_MASTER_MANAGER')",
  134.             'openapi_context' => ['summary' => 'Dismiss employee'],
  135.         ],
  136.         User::ITEM_UNDISMISS => [
  137.             'method' => 'PATCH',
  138.             'path' => 'users/{slug}/undismiss',
  139.             'input' => false,
  140.             'output' => false,
  141.             'security' => "is_granted('ROLE_HR') or is_granted('ROLE_MASTER_MANAGER')",
  142.             'openapi_context' => ['summary' => 'Cancel the dismissal employee'],
  143.         ],
  144.     ],
  145.     subresourceOperations: [
  146.         'teams_get_subresource' => [
  147.             'method' => 'GET',
  148.             'openapi_context' => [
  149.                 'summary' => 'Получить команды пользователя',
  150.                 'description' => 'Получить команды пользователя',
  151.             ],
  152.         ],
  153.     ],
  154.     attributes: [
  155.         'pagination_items_per_page' => 300,
  156.         'order' => ['slug' => 'ASC'],
  157.     ],
  158.     inputUserInput::class,
  159.     outputUserOutput::class,
  160. )]
  161. #[ApiFilter(OrLikeSearchFilter::class, properties: [
  162.     'filter_name' => 'search',
  163.     'fields' => [
  164.         'email',
  165.         'profile' => ['person.firstName''person.lastName''person.surname'],
  166.     ],
  167. ])]
  168. #[ApiFilter(OrderFilter::class, properties: ['profile.person.lastName'])]
  169. #[ApiFilter(ApiArchivesFilter::class)]
  170. #[ApiFilter(SearchFilter::class, properties: [
  171.     'workPositions.workingStatus' => SearchFilterInterface::STRATEGY_EXACT,
  172. ])]
  173. #[ORM\Entity(repositoryClass'App\Repository\UserRepository')]
  174. #[ORM\Table(name'hub_user')]
  175. class User implements UserInterfaceUuidKeyInterfaceSluggableInterfacePasswordAuthenticatedUserInterface
  176. {
  177.     use SlugAsIdTrait;
  178.     public const ITEM_FIX_TIME_ENTRIES 'fix-time-entries';
  179.     public const ITEM_UNFIX_TIME_ENTRIES 'unfix-time-entries';
  180.     public const ITEM_MISSING_PLAN_DAYS 'missing-plan-days';
  181.     public const ITEM_SET_MISSING_PLAN_DAYS 'set-missing-plan-days';
  182.     public const ITEM_UNSET_MISSING_PLAN_DAYS 'unset-missing-plan-days';
  183.     public const ITEM_SET_PLAN_DAYS 'set-plan-days';
  184.     public const PATCH_TE_OPERATION 'patch-te';
  185.     public const ITEM_DISMISS 'user-dismiss';
  186.     public const ITEM_UNDISMISS 'user-undismiss';
  187.     public const READ_GROUP 'User:read';
  188.     #[Gedmo\Slug(fields: ['email'], updatabletrueseparator'-')]
  189.     #[ApiProperty(iri'https://schema.org/identifier'identifiertrue)]
  190.     #[ORM\Column(type'string'length255uniquetrue)]
  191.     protected ?string $slug null;
  192.     #[ApiFilter(SearchFilter::class, strategySearchFilter::STRATEGY_START)]
  193.     #[Assert\NotBlank]
  194.     #[Assert\Email]
  195.     #[ORM\Column(type'string'length180uniquetrue)]
  196.     private ?string $email null;
  197.     #[ORM\Column(type'json')]
  198.     private array $roles = [];
  199.     #[ORM\Column(type'string')]
  200.     private string $password '';
  201.     #[ApiSubresource]
  202.     #[ORM\OneToOne(targetEntity'App\Entity\Profile'mappedBy'user'cascade: ['persist''remove'], fetch'EAGER')]
  203.     #[ORM\JoinColumn(nullabletrueonDelete'SET NULL')]
  204.     private ?Profile $profile null;
  205.     /**
  206.      * @var Collection<int, TimeEntry>
  207.      */
  208.     #[ORM\OneToMany(targetEntity'App\Entity\TimeControl\TimeEntry'mappedBy'user')]
  209.     private Collection $timeEntries;
  210.     #[ORM\OneToOne(targetEntity'App\Entity\Project\Manager'cascade: ['persist'], orphanRemovaltruefetch'EAGER')]
  211.     #[ORM\JoinColumn(nullabletrueonDelete'SET NULL')]
  212.     private ?Manager $manager null;
  213.     #[ORM\OneToOne(targetEntity'App\Entity\Project\Developer'cascade: ['persist'], orphanRemovaltruefetch'EAGER')]
  214.     #[ORM\JoinColumn(nullabletrueonDelete'SET NULL')]
  215.     private ?Developer $developer null;
  216.     /**
  217.      * @var Collection<int, Task>
  218.      */
  219.     #[ApiSubresource]
  220.     #[ORM\OneToMany(targetEntityTask::class, mappedBy'user')]
  221.     private Collection $tasks;
  222.     /**
  223.      * @var Collection<int, Day>
  224.      */
  225.     #[ORM\OneToMany(targetEntityDay::class, mappedBy'user')]
  226.     private Collection $days;
  227.     #[ApiSubresource]
  228.     #[ORM\ManyToMany(targetEntityTeam::class)]
  229.     #[ORM\JoinTable(name'team_members')]
  230.     private Collection $teams;
  231.     #[ORM\ManyToOne(targetEntityUnit::class)]
  232.     #[ORM\JoinColumn(nullabletrue)]
  233.     private ?Unit $unit null;
  234.     /**
  235.      * @var Collection<int, WorkPosition>
  236.      */
  237.     #[ORM\OneToMany(targetEntityWorkPosition::class, mappedBy'user')]
  238.     private Collection $workPositions;
  239.     /**
  240.      * @var Collection<int, PlanDay>
  241.      */
  242.     #[ORM\OneToMany(targetEntityPlanDay::class, mappedBy'user')]
  243.     private Collection $planDay;
  244.     #[ORM\Column(type'boolean'nullabletrue)]
  245.     private ?bool $archived null;
  246.     #[ORM\Column(type'boolean'nullablefalse)]
  247.     private bool $isTgNotify;
  248.     public function __construct()
  249.     {
  250.         $this->timeEntries = new ArrayCollection();
  251.         $this->tasks = new ArrayCollection();
  252.         $this->days = new ArrayCollection();
  253.         $this->teams = new ArrayCollection();
  254.         $this->workPositions = new ArrayCollection();
  255.         $this->planDay = new ArrayCollection();
  256.         $this->isTgNotify true;
  257.     }
  258.     public function getEmail(): ?string
  259.     {
  260.         return $this->email;
  261.     }
  262.     public function setEmail(string $email): self
  263.     {
  264.         $this->email $email;
  265.         return $this;
  266.     }
  267.     public function getUserIdentifier(): string
  268.     {
  269.         return (string) $this->email;
  270.     }
  271.     public function getUsername(): string
  272.     {
  273.         return (string) $this->email;
  274.     }
  275.     public function getRoles(): array
  276.     {
  277.         $roles $this->roles;
  278.         $roles[] = 'ROLE_USER';
  279.         return \array_unique($roles);
  280.     }
  281.     public function setRoles(array $roles): self
  282.     {
  283.         $this->roles $roles;
  284.         return $this;
  285.     }
  286.     public function getPassword(): string
  287.     {
  288.         return $this->password;
  289.     }
  290.     public function setPassword(string $password): self
  291.     {
  292.         $this->password $password;
  293.         return $this;
  294.     }
  295.     public function getSalt(): ?string
  296.     {
  297.         return null;
  298.     }
  299.     public function eraseCredentials(): void
  300.     {
  301.         // If you store any temporary, sensitive data on the user, clear it here
  302.         // $this->plainPassword = null;
  303.     }
  304.     public function getProfile(): ?Profile
  305.     {
  306.         return $this->profile;
  307.     }
  308.     public function setProfile(?Profile $profile): self
  309.     {
  310.         $this->profile $profile;
  311.         if ($profile === null) {
  312.             return $this;
  313.         }
  314.         if ($this !== $profile->getUser()) {
  315.             $profile->setUser($this);
  316.         }
  317.         return $this;
  318.     }
  319.     public function getTimeEntries(): Collection
  320.     {
  321.         return $this->timeEntries;
  322.     }
  323.     public function addTimeEntry(TimeEntry $timeEntry): self
  324.     {
  325.         if (!$this->timeEntries->contains($timeEntry)) {
  326.             $this->timeEntries[] = $timeEntry;
  327.             $timeEntry->setUser($this);
  328.         }
  329.         return $this;
  330.     }
  331.     public function removeTimeEntry(TimeEntry $timeEntry): self
  332.     {
  333.         if ($this->timeEntries->contains($timeEntry)) {
  334.             $this->timeEntries->removeElement($timeEntry);
  335.             // set the owning side to null (unless already changed)
  336.             if ($timeEntry->getUser() === $this) {
  337.                 $timeEntry->setUser(null);
  338.             }
  339.         }
  340.         return $this;
  341.     }
  342.     public function getManager(): ?Manager
  343.     {
  344.         return $this->manager;
  345.     }
  346.     public function setManager(?Manager $manager): self
  347.     {
  348.         $this->manager $manager;
  349.         return $this;
  350.     }
  351.     public function getDeveloper(): ?Developer
  352.     {
  353.         return $this->developer;
  354.     }
  355.     public function setDeveloper(?Developer $developer): self
  356.     {
  357.         $this->developer $developer;
  358.         return $this;
  359.     }
  360.     public function getTasks(): Collection
  361.     {
  362.         return $this->tasks;
  363.     }
  364.     public function addTask(Task $task): self
  365.     {
  366.         if (!$this->tasks->contains($task)) {
  367.             $this->tasks[] = $task;
  368.             $task->setUser($this);
  369.         }
  370.         return $this;
  371.     }
  372.     public function removeTask(Task $task): self
  373.     {
  374.         if ($this->tasks->contains($task)) {
  375.             $this->tasks->removeElement($task);
  376.             $task->setUser(null);
  377.         }
  378.         return $this;
  379.     }
  380.     public function getDays(): Collection
  381.     {
  382.         return $this->days;
  383.     }
  384.     public function addDay(Day $day): self
  385.     {
  386.         if (!$this->days->contains($day)) {
  387.             $this->days[] = $day;
  388.             $day->setUser($this);
  389.         }
  390.         return $this;
  391.     }
  392.     public function removeDay(Day $day): self
  393.     {
  394.         if ($this->days->contains($day)) {
  395.             $this->days->removeElement($day);
  396.             $day->setUser(null);
  397.         }
  398.         return $this;
  399.     }
  400.     public function getTeams(): Collection
  401.     {
  402.         return $this->teams;
  403.     }
  404.     public function addTeam(TeamMember $team): self
  405.     {
  406.         if (!$this->teams->contains($team)) {
  407.             $this->teams[] = $team;
  408.             $team->setUser($this);
  409.         }
  410.         return $this;
  411.     }
  412.     public function removeTeam(TeamMember $team): self
  413.     {
  414.         if ($this->teams->contains($team)) {
  415.             $this->teams->removeElement($team);
  416.         }
  417.         return $this;
  418.     }
  419.     public function getUnit(): ?Unit
  420.     {
  421.         return $this->unit;
  422.     }
  423.     public function setUnit(?Unit $unit): self
  424.     {
  425.         $this->unit $unit;
  426.         return $this;
  427.     }
  428.     public function getArchived(): ?bool
  429.     {
  430.         return $this->archived;
  431.     }
  432.     public function setArchived(?bool $archived): self
  433.     {
  434.         $this->archived $archived;
  435.         return $this;
  436.     }
  437.     public function getWorkPositions(): Collection
  438.     {
  439.         return $this->workPositions;
  440.     }
  441.     public function addWorkPosition(WorkPosition $workPosition): self
  442.     {
  443.         if (!$this->workPositions->contains($workPosition)) {
  444.             $this->workPositions[] = $workPosition;
  445.             $workPosition->setUser($this);
  446.         }
  447.         return $this;
  448.     }
  449.     /**
  450.      * рабочая позиция в заданный момент времени (по умлочанию - now).
  451.      */
  452.     public function getWorkPosition(\DateTime $onDate null): ?WorkPosition
  453.     {
  454.         $criteria WorkPositionRepository::createOnDateCriteria($onDate);
  455.         $workPositions $this->getWorkPositions();
  456.         if (!$workPositions instanceof PersistentCollection) {
  457.             return null;
  458.         }
  459.         return $workPositions->matching($criteria)->getValues()[0] ?? null;
  460.     }
  461.     public function removeWorkPosition(WorkPosition $workPosition): self
  462.     {
  463.         if ($this->workPositions->contains($workPosition)) {
  464.             $this->workPositions->removeElement($workPosition);
  465.         }
  466.         return $this;
  467.     }
  468.     public function getPlanDay(): Collection
  469.     {
  470.         return $this->planDay;
  471.     }
  472.     public function addPlanDay(PlanDay $planDay): self
  473.     {
  474.         if (!$this->planDay->contains($planDay)) {
  475.             $this->planDay[] = $planDay;
  476.             $planDay->setUser($this);
  477.         }
  478.         return $this;
  479.     }
  480.     public function removePlanDay(PlanDay $planDay): self
  481.     {
  482.         if ($this->planDay->contains($planDay)) {
  483.             $this->planDay->removeElement($planDay);
  484.         }
  485.         return $this;
  486.     }
  487.     public function isDeveloper(): bool
  488.     {
  489.         $roles $this->getRoles();
  490.         return \in_array('ROLE_DEVELOPER'$rolestrue);
  491.     }
  492.     public function isManager(): bool
  493.     {
  494.         $roles $this->getRoles();
  495.         return \in_array('ROLE_MANAGER'$rolestrue);
  496.     }
  497.     public function isMasterManager(): bool
  498.     {
  499.         $roles $this->getRoles();
  500.         return \in_array('ROLE_MASTER_MANAGER'$rolestrue);
  501.     }
  502.     public function isAdmin(): bool
  503.     {
  504.         $roles $this->getRoles();
  505.         return \in_array('ROLE_ADMIN'$rolestrue);
  506.     }
  507.     public function isTgNotify(): bool
  508.     {
  509.         return $this->isTgNotify;
  510.     }
  511.     /**
  512.      * @return $this
  513.      */
  514.     public function setIsTgNotify(bool $isTgNotify): self
  515.     {
  516.         $this->isTgNotify $isTgNotify;
  517.         return $this;
  518.     }
  519.     public function __toString(): string
  520.     {
  521.         $profile $this->getProfile();
  522.         $person = ($profile instanceof Profile) ? $profile->getPerson() : null;
  523.         $name = ($person instanceof Person) ? $person->getFullName() : '';
  524.         $result $name ?: $this->slug;
  525.         return $result ?: 'Unknown user';
  526.     }
  527. }