<?php
namespace App\Entity;
use App\Entity\Abstract\Persona;
use App\Entity\GroupTicket\PublicConnection;
use App\Entity\GroupTicket\School;
use App\Entity\GroupTicket\Teacher;
use App\Entity\GroupTicket\TransportCompany;
use App\Entity\Security\UserRole;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table('user')]
#[ORM\InheritanceType('SINGLE_TABLE')]
#[ORM\DiscriminatorColumn(name: 'type', type: 'string')]
#[ORM\DiscriminatorMap([
'admin' => Admin::class,
'teacher' => Teacher::class,
'transport' => TransportCompany::class,
'school' => School::class])
]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email', entityClass: User::class)]
abstract class User extends Persona implements UserInterface, PasswordAuthenticatedUserInterface, TwoFactorInterface
{
#[ORM\Column(length: 180, unique: true)]
#[Assert\NotBlank]
#[Assert\Email]
protected ?string $email = null;
#[ORM\Column]
private ?string $password = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $passwordChangedAt = null;
#[ORM\Column(type: 'boolean')]
private bool $isVerified = false;
#[ORM\Column(length: 20, nullable: true)]
private ?string $authCode = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $validatedAt = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $loginValidStart = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $loginValidEnd = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE, nullable: true)]
private ?\DateTimeInterface $lastLogin = null;
#[ORM\ManyToMany(targetEntity: UserRole::class, inversedBy: 'users')]
private Collection $userRoles;
#[ORM\Column(type: Types::JSON, nullable: false)]
private array $roles = [];
#[ORM\ManyToOne(inversedBy: 'users')]
private ?Tu $tu = null;
#[ORM\OneToMany(mappedBy: 'createdBy', targetEntity: Institution::class)]
private Collection $institutions;
#[ORM\OneToMany(mappedBy: 'createdBy', targetEntity: Seller::class)]
private Collection $sellers;
#[ORM\ManyToMany(targetEntity: PublicConnection::class, inversedBy: 'users')]
private Collection $groupTicketPublicConnection;
#[ORM\OneToMany(mappedBy: 'user', targetEntity: UserPasswordHistory::class, cascade: ['persist', 'remove'])]
private Collection $passwordHistory;
public function __construct()
{
$this->userRoles = new ArrayCollection();
$this->institutions = new ArrayCollection();
$this->sellers = new ArrayCollection();
$this->groupTicketPublicConnection = new ArrayCollection();
$this->passwordHistory = new ArrayCollection();
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* @deprecated since Symfony 5.3, use getUserIdentifier instead
*/
public function getUsername(): string
{
return (string) $this->email;
}
public function getRoles(): array
{
$roles = $this->roles;
if (!in_array('ROLE_USER', $roles, true)) {
$roles[] = 'ROLE_USER';
}
return array_unique($roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
public function hasRole($role): bool
{
return in_array($role, $this->getRoles()) || $this->hasUserRole($role);
}
/**
* @param string|UserRole $role
* @return bool
*/
public function hasUserRole(UserRole|string $role): bool
{
if ($role instanceof UserRole) {
return $this->userRoles->contains($role);
}
if (is_string($role)) {
foreach ($this->userRoles as $userRole) {
if ($userRole->getIdentifier() === $role) {
return true;
}
}
}
return false;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getPasswordChangedAt(): ?\DateTimeInterface
{
return $this->passwordChangedAt;
}
public function setPasswordChangedAt(?\DateTimeInterface $passwordChangedAt): static
{
$this->passwordChangedAt = $passwordChangedAt;
return $this;
}
/**
* Returning a salt is only needed, if you are not using a modern
* hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
*
* @see UserInterface
*/
public function getSalt(): ?string
{
return null;
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function isVerified(): bool
{
return $this->isVerified;
}
public function setIsVerified(bool $isVerified): self
{
$this->isVerified = $isVerified;
return $this;
}
public function getAuthCode(): ?string
{
return $this->authCode;
}
public function setAuthCode(?string $authCode): static
{
$this->authCode = $authCode;
return $this;
}
public function isEmailAuthEnabled(): bool
{
if (in_array('ROLE_TEACHER', $this->roles)) {
return false;
}
return true;
}
public function getEmailAuthRecipient(): string
{
return $this->email;
}
public function getEmailAuthCode(): string
{
if (null === $this->authCode) {
throw new \LogicException('The email authentication code was not set');
}
return $this->authCode;
}
public function setEmailAuthCode(string $authCode): void
{
$this->authCode = $authCode;
}
public function getFullName(): string
{
return $this->getName();
}
public function getValidatedAt(): ?\DateTimeInterface
{
return $this->validatedAt;
}
public function setValidatedAt(?\DateTimeInterface $validatedAt): static
{
$this->validatedAt = $validatedAt;
return $this;
}
public function getLoginValidStart(): ?\DateTimeInterface
{
return $this->loginValidStart;
}
public function setLoginValidStart(?\DateTimeInterface $loginValidStart): static
{
$this->loginValidStart = $loginValidStart;
return $this;
}
public function getLoginValidEnd(): ?\DateTimeInterface
{
return $this->loginValidEnd;
}
public function setLoginValidEnd(?\DateTimeInterface $loginValidEnd): static
{
$this->loginValidEnd = $loginValidEnd;
return $this;
}
public function getLastLogin(): ?\DateTimeInterface
{
return $this->lastLogin;
}
public function setLastLogin(?\DateTimeInterface $lastLogin): static
{
$this->lastLogin = $lastLogin;
return $this;
}
public function isExpired(): bool
{
$currentDate = new \DateTime();
$validStart = $this->getLoginValidStart();
$validEnd = $this->getLoginValidEnd();
if ($validStart !== null && $validEnd !== null) {
if ($currentDate < $validStart || $currentDate > $validEnd) {
return true;
}
} elseif ($validStart !== null && $currentDate < $validStart) {
return true;
} elseif ($validEnd !== null && $currentDate > $validEnd) {
return true;
}
return false;
}
public function updateEmailForDelete(): void
{
if(!empty($this->email)){
$this->email = time().'-'.$this->email;
}
}
public function addUserRole(UserRole $role): self
{
if (!$this->userRoles->contains($role)) {
$this->userRoles->add($role);
if(in_array($role->getIdentifier(), $this->roles) === false){
$this->roles[] = $role->getIdentifier();
}
}
return $this;
}
public function removeUserRole(UserRole $role): self
{
if ($this->userRoles->contains($role)) {
$this->userRoles->removeElement($role);
$this->roles = array_filter($this->roles, fn($r) => $r !== $role->getIdentifier());
}
return $this;
}
public function clearUserRoles(): self
{
$this->userRoles->clear();
$this->roles = [];
return $this;
}
public function getUserRoles(): Collection
{
return $this->userRoles;
}
public function getTu(): ?Tu
{
return $this->tu;
}
public function setTu(?Tu $tu): static
{
$this->tu = $tu;
return $this;
}
/**
* @return Collection<int, Institution>
*/
public function getInstitutions(): Collection
{
return $this->institutions;
}
public function addInstitution(Institution $institution): static
{
if (!$this->institutions->contains($institution)) {
$this->institutions->add($institution);
$institution->setCreatedBy($this);
}
return $this;
}
public function removeInstitution(Institution $institution): static
{
if ($this->institutions->removeElement($institution)) {
// set the owning side to null (unless already changed)
if ($institution->getCreatedBy() === $this) {
$institution->setCreatedBy(null);
}
}
return $this;
}
/**
* @return Collection<int, Seller>
*/
public function getSellers(): Collection
{
return $this->sellers;
}
public function addSeller(Seller $seller): static
{
if (!$this->sellers->contains($seller)) {
$this->sellers->add($seller);
$seller->setCreatedBy($this);
}
return $this;
}
public function removeSeller(Seller $seller): static
{
if ($this->sellers->removeElement($seller)) {
// set the owning side to null (unless already changed)
if ($seller->getCreatedBy() === $this) {
$seller->setCreatedBy(null);
}
}
return $this;
}
/**
* @return Collection<int, PublicConnection>
*/
public function getGroupTicketPublicConnection(): Collection
{
return $this->groupTicketPublicConnection;
}
public function addGroupTicketPublicConnection(PublicConnection $groupTicketPublicConnection): static
{
if (!$this->groupTicketPublicConnection->contains($groupTicketPublicConnection)) {
$this->groupTicketPublicConnection->add($groupTicketPublicConnection);
}
return $this;
}
public function removeGroupTicketPublicConnection(PublicConnection $groupTicketPublicConnection): static
{
$this->groupTicketPublicConnection->removeElement($groupTicketPublicConnection);
return $this;
}
public function getPasswordHistory(): Collection
{
return $this->passwordHistory;
}
public function addPasswordHistory(UserPasswordHistory $entry): static
{
if (!$this->passwordHistory->contains($entry)) {
$this->passwordHistory->add($entry);
$entry->setUser($this);
}
return $this;
}
public function clearPasswordHistory(): static
{
foreach ($this->passwordHistory as $entry) {
$this->passwordHistory->removeElement($entry);
}
return $this;
}
}