src/Entity/Customer.php line 78

  1. <?php
  2. namespace App\Entity;
  3. use Doctrine\ORM\Mapping as ORM,
  4.     Doctrine\DBAL\Types\Types,
  5.     Doctrine\Common\Collections\ArrayCollection,
  6.     Doctrine\Common\Collections\Collection;
  7. use Symfony\Component\Serializer\Annotation\Groups,
  8.     Symfony\Component\Validator\Constraints as Assert,
  9.     Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface,
  10.     Symfony\Component\Security\Core\User\UserInterface,
  11.     Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface,
  12.     Symfony\Component\Validator\Constraint;
  13. use ApiPlatform\Metadata\ApiResource,
  14.     ApiPlatform\Metadata\ApiProperty,
  15.     ApiPlatform\Metadata\Get,
  16.     ApiPlatform\Metadata\GetCollection,
  17.     ApiPlatform\Metadata\Post,
  18.     ApiPlatform\Metadata\Put,
  19.     ApiPlatform\Metadata\Delete,
  20.     ApiPlatform\Metadata\ApiFilter,
  21.     ApiPlatform\Doctrine\Orm\Filter\SearchFilter,
  22.     ApiPlatform\Doctrine\Orm\Filter\BooleanFilter,
  23.     ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
  24. use App\Command\CustomerNotifier;
  25. use App\Entity\Trait\IdTrait,
  26.     App\Entity\Trait\UuidTrait,
  27.     App\Entity\Trait\TimestampableTrait,
  28.     App\Entity\Trait\StatTrait,
  29.     App\Entity\Interface\SimpleEntityInterface,
  30.     App\Entity\Interface\StatableInterface,
  31.     App\Entity\Interface\PasswordResetableInterface;
  32. use App\Enum\Language,
  33.     App\Validator\Constraints\User as CustomAssert,
  34.     App\Repository\CustomerRepository,
  35.     App\StateProcessor\CustomerRegister\PostRegisterProcessor,
  36.     App\Doctrine\DBAL\Types\CustomerLoginMethodsType,
  37.     App\Enum\CustomerLoginMethod;
  38. #[ApiResource(
  39.     description'Customers',
  40.     normalizationContext: ['groups' => ['read''read:' self::class]],
  41.     denormalizationContext: ['groups' => ['write']],
  42.     order: ['createdAt' => 'desc'],
  43.     operations: [
  44.         new GetCollection(
  45.             security'is_granted("' self::class . '")'
  46.         ),
  47.         new Post(
  48.             uriTemplate'/customers/register',
  49.             denormalizationContext: ['groups' => ['register']],
  50.             processorPostRegisterProcessor::class,
  51.             validationContext: ['groups' => [Constraint::DEFAULT_GROUP'register']],
  52.         ),
  53.         new Post(
  54.             processorPostRegisterProcessor::class,
  55.             validationContext: ['groups' => [Constraint::DEFAULT_GROUP'post']],
  56.         ),
  57.         new Get(
  58.             security'is_granted("' self::class . '")'
  59.         ),
  60.         new Put(
  61.             security'is_granted("' self::class . '")'
  62.         ),
  63.         new Delete(
  64.             security'is_granted("' self::class . '")'
  65.         )
  66.     ],
  67.     extraProperties: ['standard_put' => false],
  68. )]
  69. #[ApiFilter(SearchFilter::class, properties: ['email' => 'partial''fullName' => 'partial'])]
  70. #[ApiFilter(BooleanFilter::class, properties: ['stat'])]
  71. #[ApiFilter(OrderFilter::class, properties: ['email''fullName''stat''createdAt''updatedAt'])]
  72. #[ORM\Entity(repositoryClassCustomerRepository::class)]
  73. class Customer implements
  74.     SimpleEntityInterface,
  75.     StatableInterface,
  76.     UserInterface,
  77.     PasswordAuthenticatedUserInterface,
  78.     PasswordResetableInterface
  79. {
  80.     use IdTrait,
  81.         UuidTrait,
  82.         TimestampableTrait,
  83.         StatTrait;
  84.     const MAX_PREVIOUS_PASSWORDS 5;
  85.     #[ApiProperty(description'Email')]
  86.     #[Groups(['read''write''register'])]
  87.     #[Assert\NotBlank]
  88.     #[Assert\Email]
  89.     #[ORM\Column(typeTypes::STRINGlength191uniquetrue)]
  90.     private string $email;
  91.     #[ApiProperty(description'Persisted password')]
  92.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  93.     private ?string $password null;
  94.     #[ApiProperty(description'New password')]
  95.     #[Groups(['write''register'])]
  96.     #[Assert\NotBlank(groups: ['post''register'])]
  97.     #[Assert\Length(max50groups: [Constraint::DEFAULT_GROUP'profile'])]
  98.     #[Assert\Regex(
  99.         pattern'/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-\.]).{8,}$/',
  100.         match: true,
  101.         message'Password must consist of at least 8 characters (upper case, lower case, number, special character)',
  102.         groups: [Constraint::DEFAULT_GROUP'profile']
  103.     )]
  104.     #[Assert\NotCompromisedPassword(groups: [Constraint::DEFAULT_GROUP'profile'])]
  105.     #[CustomAssert\PreviousPasswords(groups: [Constraint::DEFAULT_GROUP'profile'])]
  106.     private ?string $rawPassword null;
  107.     #[ApiProperty(description'New password repeat')]
  108.     #[Groups(['write''register'])]
  109.     #[Assert\Expression(
  110.         expression'value === this.getRawPassword()',
  111.         message'Passwords do not match.',
  112.         groups: ['post''register''profile']
  113.     )]
  114.     private ?string $rawPasswordRepeat null;
  115.     #[ApiProperty(description'Current password')]
  116.     #[CustomAssert\CurrentPassword(groups: ['profile'])]
  117.     private ?string $currentPassword null;
  118.     #[ApiProperty(description'Previous passwords')]
  119.     #[ORM\Column(typeTypes::JSON)]
  120.     private array $previousPasswords = [];
  121.     #[ApiProperty(description'Name and surname')]
  122.     #[Groups(['read''write''register'])]
  123.     #[Assert\NotBlank]
  124.     #[Assert\Length(min3)]
  125.     #[ORM\Column(typeTypes::STRINGlength255)]
  126.     private string $fullName;
  127.     #[ApiProperty(description'Is regulations accepted')]
  128.     #[Groups(['register'])]
  129.     #[Assert\IsTrue(groups: ['register'])]
  130.     private bool $isRegulationsAccepted false;
  131.     #[ApiProperty(description'Is privacy policy accepted')]
  132.     #[Groups(['register'])]
  133.     #[Assert\IsTrue(groups: ['register'])]
  134.     private bool $isPrivacyPolicyAccepted false;
  135.     #[ApiProperty(description'Login methods')]
  136.     #[ORM\Column(typeCustomerLoginMethodsType::NAME)]
  137.     private array $loginMethods = [];
  138.     #[ApiProperty(description'Google id')]
  139.     #[Groups(['read:' self::class])]
  140.     #[ORM\Column(typeTypes::STRINGlength1023nullabletrue)]
  141.     private ?string $googleId null;
  142.     #[ApiProperty(description'Google hash')]
  143.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  144.     private ?string $googleHash null;
  145.     #[ApiProperty(description'Google hash generated at')]
  146.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  147.     private ?\DateTimeImmutable $googleHashGeneratedAt null;
  148.     #[ApiProperty(description'Orcid id')]
  149.     #[Groups(['read:' self::class])]
  150.     #[ORM\Column(typeTypes::STRINGlength1023nullabletrue)]
  151.     private ?string $orcidId null;
  152.     #[ApiProperty(description'Orcid hash')]
  153.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  154.     private ?string $orcidHash null;
  155.     #[ApiProperty(description'Orcid hash generated at')]
  156.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  157.     private ?\DateTimeImmutable $orcidHashGeneratedAt null;
  158.     #[ApiProperty(description'Register hash')]
  159.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  160.     private ?string $registerHash null;
  161.     #[ApiProperty(description'Register hash generated at')]
  162.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  163.     private ?\DateTimeImmutable $registerHashGeneratedAt null;
  164.     #[ApiProperty(description'Reset password hash')]
  165.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  166.     private ?string $resetPasswordHash null;
  167.     #[ApiProperty(description'Reset password hash generated at')]
  168.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  169.     private ?\DateTimeImmutable $resetPasswordHashGeneratedAt null;
  170.     #[ApiProperty(description'Is confirmed')]
  171.     #[Groups(['read:' self::class])]
  172.     #[ORM\Column(typeTypes::BOOLEANoptions: ['default' => false])]
  173.     private bool $isConfirmed false;
  174.     #[ApiProperty(description'Register language')]
  175.     #[Groups(['read:' self::class, 'register'])]
  176.     #[ORM\Column(
  177.         typeTypes::STRING,
  178.         enumTypeLanguage::class,
  179.         length255,
  180.         options: ['default' => Language::EN]
  181.     )]
  182.     private Language $registerLanguage Language::EN;
  183.     #[ApiProperty(description'Last login at')]
  184.     #[Groups(['read:' self::class])]
  185.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLE)]
  186.     private \DateTimeImmutable $lastLoginAt;
  187.     #[ApiProperty(description'Directories')]
  188.     #[ORM\OneToMany(targetEntityCustomerDirectory::class, mappedBy'parent'cascade: ['persist''remove'])]
  189.     #[ORM\OrderBy(['createdAt' => 'desc'])]
  190.     private Collection $directories;
  191.     private ?array $directoriesItemsUuids null;
  192.     #[ORM\OneToMany(targetEntityCustomerNotification::class, mappedBy'parent'cascade: ['persist''remove'])]
  193.     #[ORM\OrderBy(['createdAt' => 'desc'])]
  194.     private Collection $notifications;
  195.     #[ORM\OneToMany(targetEntityCustomerSentNotification::class, mappedBy'parent'cascade: ['persist''remove'])]
  196.     #[ORM\OrderBy(['createdAt' => 'desc'])]
  197.     private Collection $sentNotifications;
  198.     #[ApiProperty(description'Delete account hash generated at')]
  199.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLEnullabletrue)]
  200.     private ?\DateTimeImmutable $deleteAccountHashGeneratedAt null;
  201.     #[ApiProperty(description'Delete account hash')]
  202.     #[ORM\Column(typeTypes::STRINGlength255nullabletrue)]
  203.     private ?string $deleteAccountHash null;
  204.     public function __construct(string $email)
  205.     {
  206.         $this->setUuid();
  207.         $this->email $email;
  208.         $this->lastLoginAt = new \DateTimeImmutable();
  209.         $this->directories = new ArrayCollection();
  210.         $this->notifications = new ArrayCollection();
  211.         $this->sentNotifications = new ArrayCollection();
  212.         $this->createdAt = new \DateTimeImmutable();
  213.         $this->updatedAt = new \DateTimeImmutable();
  214.     }
  215.     public function getEmail(): string
  216.     {
  217.         return $this->email;
  218.     }
  219.     public function getPassword(): ?string
  220.     {
  221.         return $this->password;
  222.     }
  223.     public function getRawPassword(): ?string
  224.     {
  225.         return $this->rawPassword;
  226.     }
  227.     public function setRawPassword(?string $rawPasswordUserPasswordHasherInterface $encoder): self
  228.     {
  229.         if (! $rawPassword) {
  230.             return $this;
  231.         }
  232.         $this->rawPassword $rawPassword;
  233.         $this->password $encoder->hashPassword($this$rawPassword);
  234.         if (count($this->previousPasswords) >= self::MAX_PREVIOUS_PASSWORDS) {
  235.             $this->previousPasswords array_slice($this->previousPasswords1);
  236.         }
  237.         $this->previousPasswords[] = password_hash($rawPasswordPASSWORD_DEFAULT);
  238.         $this->resetPasswordHash null;
  239.         $this->resetPasswordHashGeneratedAt null;
  240.         $this->addLoginMethod(CustomerLoginMethod::PASSWORD);
  241.         return $this;
  242.     }
  243.     public function getRawPasswordRepeat(): ?string
  244.     {
  245.         return $this->rawPasswordRepeat;
  246.     }
  247.     public function setRawPasswordRepeat(?string $rawPasswordRepeat): self
  248.     {
  249.         $this->rawPasswordRepeat $rawPasswordRepeat;
  250.         return $this;
  251.     }
  252.     public function setHashedPassword(string $hashedPassword): self
  253.     {
  254.         $this->password $hashedPassword;
  255.         return $this;
  256.     }
  257.     public function getCurrentPassword(): ?string
  258.     {
  259.         return $this->currentPassword;
  260.     }
  261.     public function setCurrentPassword(?string $currentPassword): self
  262.     {
  263.         $this->currentPassword $currentPassword;
  264.         return $this;
  265.     }
  266.     public function getPreviousPasswords(): array
  267.     {
  268.         return $this->previousPasswords;
  269.     }
  270.     public function getFullName(): string
  271.     {
  272.         return $this->fullName;
  273.     }
  274.     public function setFullName(string $fullName): self
  275.     {
  276.         $this->fullName $fullName;
  277.         return $this;
  278.     }
  279.     public function getIsRegulationsAccepted(): bool
  280.     {
  281.         return $this->isRegulationsAccepted;
  282.     }
  283.     public function setIsRegulationsAccepted(bool $isRegulationsAccepted): self
  284.     {
  285.         $this->isRegulationsAccepted $isRegulationsAccepted;
  286.         return $this;
  287.     }
  288.     public function getIsPrivacyPolicyAccepted(): bool
  289.     {
  290.         return $this->isPrivacyPolicyAccepted;
  291.     }
  292.     public function setIsPrivacyPolicyAccepted(bool $isPrivacyPolicyAccepted): self
  293.     {
  294.         $this->isPrivacyPolicyAccepted $isPrivacyPolicyAccepted;
  295.         return $this;
  296.     }
  297.     public function getLoginMethods(): array
  298.     {
  299.         return $this->loginMethods;
  300.     }
  301.     private function addLoginMethod(CustomerLoginMethod $method): self
  302.     {
  303.         if ($this->isLoginMethodAvailable($method)) {
  304.             return $this;
  305.         }
  306.         $this->loginMethods[] = $method;
  307.         return $this;
  308.     }
  309.     public function isLoginMethodAvailable(CustomerLoginMethod $method): bool
  310.     {
  311.         return in_array($method$this->loginMethods);
  312.     }
  313.     public function isPasswordLoginMethodAvailable(): bool
  314.     {
  315.         return in_array(CustomerLoginMethod::PASSWORD$this->loginMethods);
  316.     }
  317.     public function getGoogleId(): ?string
  318.     {
  319.         return $this->googleId;
  320.     }
  321.     public function setGoogleId(string $googleId): self
  322.     {
  323.         $this->googleId $googleId;
  324.         return $this;
  325.     }
  326.     public function setGoogleHash(string $googleHash): self
  327.     {
  328.         $this->googleHash $googleHash;
  329.         $this->googleHashGeneratedAt = new \DateTimeImmutable();
  330.         return $this;
  331.     }
  332.     public function getGoogleHash(): ?string
  333.     {
  334.         return $this->googleHash;
  335.     }
  336.     public function getGoogleHashGeneratedAt(): ?\DateTimeImmutable
  337.     {
  338.         return $this->googleHashGeneratedAt;
  339.     }
  340.     public function addGoogleLogin(): self
  341.     {
  342.         if ($this->isLoginMethodAvailable(CustomerLoginMethod::GOOGLE)) {
  343.             return $this;
  344.         }
  345.         $this->addLoginMethod(CustomerLoginMethod::GOOGLE);
  346.         $this->googleHash null;
  347.         $this->googleHashGeneratedAt null;
  348.         return $this;
  349.     }
  350.     public function getOrcidId(): ?string
  351.     {
  352.         return $this->orcidId;
  353.     }
  354.     public function setOrcidId(string $orcidId): self
  355.     {
  356.         $this->orcidId $orcidId;
  357.         return $this;
  358.     }
  359.     public function setOrcidHash(string $orcidHash): self
  360.     {
  361.         $this->orcidHash $orcidHash;
  362.         $this->orcidHashGeneratedAt = new \DateTimeImmutable();
  363.         return $this;
  364.     }
  365.     public function getOrcidHash(): ?string
  366.     {
  367.         return $this->orcidHash;
  368.     }
  369.     public function getOrcidHashGeneratedAt(): ?\DateTimeImmutable
  370.     {
  371.         return $this->orcidHashGeneratedAt;
  372.     }
  373.     public function addOrcidLogin(): self
  374.     {
  375.         if ($this->isLoginMethodAvailable(CustomerLoginMethod::ORCID)) {
  376.             return $this;
  377.         }
  378.         $this->addLoginMethod(CustomerLoginMethod::ORCID);
  379.         $this->orcidHash null;
  380.         $this->orcidHashGeneratedAt null;
  381.         return $this;
  382.     }
  383.     public function setRegisterHash(string $registerHash): self
  384.     {
  385.         $this->registerHash $registerHash;
  386.         $this->registerHashGeneratedAt = new \DateTimeImmutable();
  387.         return $this;
  388.     }
  389.     public function getRegisterHash(): ?string
  390.     {
  391.         return $this->registerHash;
  392.     }
  393.     public function getRegisterHashGeneratedAt(): ?\DateTimeImmutable
  394.     {
  395.         return $this->registerHashGeneratedAt;
  396.     }
  397.     public function setResetPasswordHash(string $hash): self
  398.     {
  399.         $this->resetPasswordHash $hash;
  400.         $this->resetPasswordHashGeneratedAt = new \DateTimeImmutable();
  401.         return $this;
  402.     }
  403.     public function getResetPasswordHash(): ?string
  404.     {
  405.         return $this->resetPasswordHash;
  406.     }
  407.     public function getResetPasswordHashGeneratedAt(): ?\DateTimeImmutable
  408.     {
  409.         return $this->resetPasswordHashGeneratedAt;
  410.     }
  411.     public function getIsConfirmed(): bool
  412.     {
  413.         return $this->isConfirmed;
  414.     }
  415.     public function confirmRegister(): self
  416.     {
  417.         if ($this->isConfirmed) {
  418.             return $this;
  419.         }
  420.         $this->isConfirmed true;
  421.         $this->stat true;
  422.         $this->registerHash null;
  423.         $this->registerHashGeneratedAt null;
  424.         return $this;
  425.     }
  426.     public function getRegisterLanguage(): Language
  427.     {
  428.         return $this->registerLanguage;
  429.     }
  430.     public function setRegisterLanguage(Language $registerLanguage): self
  431.     {
  432.         $this->registerLanguage $registerLanguage;
  433.         return $this;
  434.     }
  435.     public function getLastLoginAt(): \DateTimeImmutable
  436.     {
  437.         return $this->lastLoginAt;
  438.     }
  439.     public function setLastLoginAt(\DateTimeImmutable $lastLoginAt): self
  440.     {
  441.         $this->lastLoginAt $lastLoginAt;
  442.         return $this;
  443.     }
  444.     /**
  445.      * @return Collection|CustomerDirectory[]
  446.      */
  447.     public function getDirectories(): Collection
  448.     {
  449.         return $this->directories;
  450.     }
  451.     public function addDirectory(CustomerDirectory $directory): self
  452.     {
  453.         if ($this->directories->contains($directory)) {
  454.             return $this;
  455.         }
  456.         $this->directories[] = $directory;
  457.         return $this;
  458.     }
  459.     public function removeDirectory(CustomerDirectory $directory): self
  460.     {
  461.         $this->directories->removeElement($directory);
  462.         return $this;
  463.     }
  464.     /**
  465.      * @return Collection|CustomerNotification[]
  466.      */
  467.     public function getNotifications(): Collection
  468.     {
  469.         return $this->notifications;
  470.     }
  471.     public function addNotification(CustomerNotification $notification): self
  472.     {
  473.         if ($this->notifications->contains($notification)) {
  474.             return $this;
  475.         }
  476.         $this->notifications[] = $notification;
  477.         return $this;
  478.     }
  479.     public function removeNotification(CustomerNotification $notification): self
  480.     {
  481.         $this->notifications->removeElement($notification);
  482.         return $this;
  483.     }
  484.     public function hasNotification(Journal $journal): bool
  485.     {
  486.         return null !== $this->notifications->findFirst(
  487.             fn(int $keyCustomerNotification $notification) =>
  488.                 $notification->getStat() && $notification->getJournal() === $journal
  489.         );
  490.     }
  491.     /**
  492.      * @return Collection|CustomerSentNotification[]
  493.      */
  494.     public function getSentNotifications(): Collection
  495.     {
  496.         return $this->sentNotifications;
  497.     }
  498.     public function addSentNotification(CustomerSentNotification $sentNotification): self
  499.     {
  500.         if ($this->sentNotifications->contains($sentNotification)) {
  501.             return $this;
  502.         }
  503.         $this->sentNotifications[] = $sentNotification;
  504.         return $this;
  505.     }
  506.     public function removeSentNotification(CustomerSentNotification $sentNotification): self
  507.     {
  508.         $this->sentNotifications->removeElement($sentNotification);
  509.         return $this;
  510.     }
  511.     public function getDirectoriesItemsUuids(): array
  512.     {
  513.         if (! $this->directoriesItemsUuids) {
  514.             $this->directoriesItemsUuids = [];
  515.             /** @var CustomerDirectory $directory */
  516.             foreach ($this->getDirectories() as $directory) {
  517.                 /** @var CustomerDirectoryItem $item */
  518.                 foreach ($directory->getItems() as $item) {
  519.                     $this->directoriesItemsUuids[] = $item->getVolume()?->getUuid();
  520.                     $this->directoriesItemsUuids[] = $item->getIssue()?->getUuid();
  521.                     $this->directoriesItemsUuids[] = $item->getArticle()?->getUuid();
  522.                 }
  523.             }
  524.         }
  525.         return $this->directoriesItemsUuids;
  526.     }
  527.     public function getUsername(): string
  528.     {
  529.         return $this->email;
  530.     }
  531.     public function getUserIdentifier(): string
  532.     {
  533.         return $this->email;
  534.     }
  535.     public function getRoles(): array
  536.     {
  537.         return ['ROLE_CUSTOMER'];
  538.     }
  539.     public function getSalt(): ?string
  540.     {
  541.         return null;
  542.     }
  543.     public function eraseCredentials(): void
  544.     {
  545.         return;
  546.     }
  547.     public function getDeleteAccountHashGeneratedAt(): ?\DateTimeImmutable
  548.     {
  549.         return $this->deleteAccountHashGeneratedAt;
  550.     }
  551.     public function setDeleteAccountHashGeneratedAt(?\DateTimeImmutable $deleteAccountHashGeneratedAt): self
  552.     {
  553.         $this->deleteAccountHashGeneratedAt $deleteAccountHashGeneratedAt;
  554.         return $this;
  555.     }
  556.     public function getDeleteAccountHash(): ?string
  557.     {
  558.         return $this->deleteAccountHash;
  559.     }
  560.     public function setDeleteAccountHash(?string $deleteAccountHash): self
  561.     {
  562.         $this->deleteAccountHash $deleteAccountHash;
  563.         return $this;
  564.     }
  565. }