<?php
namespace App\Entity;
use App\Repository\UserRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 180, unique: true)]
private ?string $email = null;
#[ORM\Column]
private array $roles = [];
/**
* @var string The hashed password
*/
#[ORM\Column]
private ?string $password = null;
#[ORM\Column(type: 'boolean')]
private $isVerified = false;
#[ORM\OneToMany(targetEntity: Notification::class, mappedBy: 'user')]
private Collection $notifications;
#[ORM\ManyToMany(targetEntity: Shop::class, mappedBy: 'manager')]
private Collection $shops;
#[ORM\Column]
private ?DateTimeImmutable $createdAt = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $firstname = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $lastname = null;
#[ORM\Column(length: 20, nullable: true)]
private ?string $gender = null;
#[ORM\Column(length: 50, nullable: true)]
private ?string $kycStatus = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $selfieSubmitted = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $frontDocumentSubmitted = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $backDocumentSubmitted = null;
#[ORM\Column(nullable: true)]
private ?DateTimeImmutable $kycSubmittedAt = null;
#[ORM\Column(nullable: true)]
private ?DateTimeImmutable $kycVerifiedAt = null;
#[ORM\OneToMany(targetEntity: Address::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
private Collection $addresses;
#[ORM\Column(length: 50, nullable: true)]
private ?string $phone = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $profilePicture = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $resetToken = null;
#[ORM\Column(nullable: true)]
private ?DateTimeImmutable $passwordRequestedAt = null;
public function __construct()
{
$this->notifications = new ArrayCollection();
$this->shops = new ArrayCollection();
$this->addresses = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): static
{
$this->email = $email;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return (string)$this->email;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique($roles);
}
public function setRoles(array $roles): static
{
$this->roles = $roles;
return $this;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): static
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials(): void
{
// 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): static
{
$this->isVerified = $isVerified;
return $this;
}
/**
* @return Collection<int, Notification>
*/
public function getNotifications(): Collection
{
return $this->notifications;
}
public function addNotification(Notification $notification): static
{
if (!$this->notifications->contains($notification)) {
$this->notifications->add($notification);
$notification->setUser($this);
}
return $this;
}
public function removeNotification(Notification $notification): static
{
if ($this->notifications->removeElement($notification)) {
// set the owning side to null (unless already changed)
if ($notification->getUser() === $this) {
$notification->setUser(null);
}
}
return $this;
}
/**
* @return Collection<int, Shop>
*/
public function getShops(): Collection
{
return $this->shops;
}
public function addShop(Shop $shop): static
{
if (!$this->shops->contains($shop)) {
$this->shops->add($shop);
$shop->addManager($this);
}
return $this;
}
public function removeShop(Shop $shop): static
{
if ($this->shops->removeElement($shop)) {
$shop->removeManager($this);
}
return $this;
}
public function getCreatedAt(): ?DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(DateTimeImmutable $createdAt): static
{
$this->createdAt = $createdAt;
return $this;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(?string $firstname): static
{
$this->firstname = $firstname;
return $this;
}
public function getLastname(): ?string
{
return $this->lastname;
}
public function setLastname(?string $lastname): static
{
$this->lastname = $lastname;
return $this;
}
public function getGender(): ?string
{
return $this->gender;
}
public function setGender(?string $gender): static
{
$this->gender = $gender;
return $this;
}
public function getSelfieSubmitted(): ?string
{
return $this->selfieSubmitted;
}
public function setSelfieSubmitted(?string $selfieSubmitted): static
{
$this->selfieSubmitted = $selfieSubmitted;
return $this;
}
public function getFrontDocumentSubmitted(): ?string
{
return $this->frontDocumentSubmitted;
}
public function setFrontDocumentSubmitted(?string $frontDocumentSubmitted): static
{
$this->frontDocumentSubmitted = $frontDocumentSubmitted;
return $this;
}
public function getBackDocumentSubmitted(): ?string
{
return $this->backDocumentSubmitted;
}
public function setBackDocumentSubmitted(?string $backDocumentSubmitted): static
{
$this->backDocumentSubmitted = $backDocumentSubmitted;
return $this;
}
public function getKycSubmittedAt(): ?DateTimeImmutable
{
return $this->kycSubmittedAt;
}
public function setKycSubmittedAt(?DateTimeImmutable $kycSubmittedAt): static
{
$this->kycSubmittedAt = $kycSubmittedAt;
return $this;
}
public function getKycVerifiedAt(): ?DateTimeImmutable
{
return $this->kycVerifiedAt;
}
public function setKycVerifiedAt(?DateTimeImmutable $kycVerifiedAt): static
{
$this->kycVerifiedAt = $kycVerifiedAt;
return $this;
}
/**
* @return string|null
*/
public function getKycStatus(): ?string
{
return $this->kycStatus;
}
/**
* @param string|null $kycStatus
*/
public function setKycStatus(?string $kycStatus): void
{
$this->kycStatus = $kycStatus;
}
/**
* @return Collection|Address[]
*/
public function getAddresses(): Collection
{
return $this->addresses;
}
public function addAddress(Address $address): self
{
if (!$this->addresses->contains($address)) {
$this->addresses[] = $address;
$address->setUser($this);
}
return $this;
}
public function removeAddress(Address $address): self
{
if ($this->addresses->removeElement($address)) {
if ($address->getUser() === $this) {
$address->setUser(null);
}
}
return $this;
}
/**
* Retourne l'adresse par défaut si définie
*/
public function getDefaultAddress(): ?Address
{
foreach ($this->addresses as $address) {
if ($address->getIsDefault()) {
return $address;
}
}
return null;
}
public function __toString(): string
{
return $this->getUserIdentifier();
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): static
{
$this->phone = $phone;
return $this;
}
public function getProfilePicture(): ?string
{
return $this->profilePicture;
}
public function setProfilePicture(?string $profilePicture): static
{
$this->profilePicture = $profilePicture;
return $this;
}
public function getProfilePictureUrl(): string
{
if ($this->profilePicture) {
// Si c'est déjà une URL complète, la retourner telle quelle
if (str_starts_with($this->profilePicture, 'http')) {
return $this->profilePicture;
}
// Sinon, retourner le chemin relatif
return $this->profilePicture;
}
// Image par défaut avec initiales
$initials = '';
if ($this->firstname) {
$initials .= mb_substr($this->firstname, 0, 1);
}
if ($this->lastname) {
$initials .= mb_substr($this->lastname, 0, 1);
}
if (empty($initials) && $this->email) {
$initials = mb_substr($this->email, 0, 1);
}
return 'https://ui-avatars.com/api/?name=' . urlencode($initials ?: 'U') . '&background=667eea&color=fff&size=200';
}
public function getResetToken(): ?string
{
return $this->resetToken;
}
public function setResetToken(?string $resetToken): static
{
$this->resetToken = $resetToken;
return $this;
}
public function getPasswordRequestedAt(): ?DateTimeImmutable
{
return $this->passwordRequestedAt;
}
public function setPasswordRequestedAt(?DateTimeImmutable $passwordRequestedAt): static
{
$this->passwordRequestedAt = $passwordRequestedAt;
return $this;
}
public function isPasswordRequestNonExpired(int $ttl = 3600): bool
{
if ($this->passwordRequestedAt === null) {
return false;
}
$expirationDate = $this->passwordRequestedAt->modify("+{$ttl} seconds");
return $expirationDate >= new DateTimeImmutable('now');
}
}