<?php
namespace App\Entity;
use App\Repository\TransactionRepository;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Intl\Countries;
use Symfony\Component\Intl\Exception\MissingResourceException;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*
* @ORM\Table(
* name="user",
* indexes={
*
* @ORM\Index(columns={"created_at"}),
* @ORM\Index(columns={"last_login"}),
* @ORM\Index(columns={"username"}),
* @ORM\Index(columns={"email"})
* }
* )
*
* @ORM\InheritanceType("SINGLE_TABLE")
*
* @ORM\DiscriminatorColumn(name="type", type="string")
*
* @ORM\DiscriminatorMap({
* "user" = "PrivateUser",
* "pro" = "ProUser",
* })
*
* We pass the entityClass so that uniqueness is checked when PrivateUser and ProUser are instanced.
*
* @UniqueEntity(
* fields = "username",
* entityClass="App\Entity\User",
* groups={"registration_pro_2", "Default", "Registration", "portugal", "belgium"},
* message="fos_user.username.already_used"
* )
* @UniqueEntity(
* fields = "email",
* entityClass="App\Entity\User",
* groups={"registration_pro_2", "Default", "Registration", "portugal", "belgium"},
* message="fos_user.email.already_used"
* )
*
* @Vich\Uploadable
*/
abstract class User extends BaseUser
{
public const TYPE_PRIVATE = 'user';
public const TYPE_SOCIETY = 'society';
public const TYPE_PRO = 'pro';
public const SF_TYPE_PROFESSIONAL = 'Professionnel';
public const SF_TYPE_SOCIETY = 'Société';
public const SF_TYPE_PERSON = 'Particulier';
public const ORIGIN_VPAUTO = 'vpauto';
public const ORIGIN_SHOWVROOM = 'showvroom';
/**
* @ORM\Id
*
* @ORM\Column(type="bigint")
*
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=20, nullable=true)
*
* @Assert\NotBlank(groups={"profile"})
*/
protected $title;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_2"}, message="frontend.profile.lastname.blank")
*/
protected $lastname;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_2"}, message="frontend.profile.firstname.blank")
*/
protected $firstname;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_1"}, message="frontend.profile.address.blank")
*/
protected $address;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $addressComplement;
/**
* @ORM\Column(type="string", length=50, name="zip_code", nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_1"}, message="frontend.profile.zipCode.blank")
*/
protected $zipCode;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_1"}, message="frontend.profile.city.blank")
*/
protected $city;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info", "registration_pro_1"}, message="frontend.profile.country.blank")
*/
protected $country;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
protected $referralSource;
/**
* 40 is the maximal length in Salesforce, we need to accept data that is imported from Salesforce.
*
* @ORM\Column(type="string", length=40, nullable=true)
*
* @Assert\NotBlank(groups={"registration_pro_2"}, message="frontend.page.register_pro.form.required.phone")
*/
protected $phone;
/**
* @ORM\Column(type="string", length=30, nullable=true)
*
* @Assert\NotBlank(groups={"profile", "payment_check_info"}, message="frontend.profile.mobile.blank")
*/
protected $mobile;
/**
* @Gedmo\Timestampable(on="create")
*
* @ORM\Column(type="datetime", name="created_at")
*/
protected $createdAt;
/**
* @Gedmo\Timestampable(on="update")
*
* @ORM\Column(type="datetime", name="updated_at")
*/
protected $updatedAt;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
protected $newsletter;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected $lastOptinChangeDate;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Auction", mappedBy="users")
*/
protected $auctions;
/**
* @ORM\Column(type="boolean")
*/
protected $needsTransaction;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
protected $society;
/**
* @ORM\Column(type="boolean")
*/
protected $smsOptin;
/**
* locked was removed from FOSUserBundle,
* see https://github.com/FriendsOfSymfony/FOSUserBundle/commit/7ad2a4ba08a4f038e49227abf1b893968af1c995.
*
* @var bool
*
* @ORM\Column(type="boolean")
*/
protected $locked;
/**
* @ORM\Column(type="string", nullable=true)
*
* @Assert\NotBlank(groups={"registration_pro"}, message="assert.user.language.not_blank")
*/
protected $language;
/**
* @Vich\UploadableField(mapping="user_avatar", fileNameProperty="avatar")
*
* @Assert\NotBlank(groups={"avatar"})
*
* @Assert\Image(
* minWidth = 200,
* maxWidth = 1800,
* minHeight = 200,
* maxHeight = 1800,
* groups={"avatar"}
* )
*
* @Assert\File(
* maxSize = "8M",
* groups={"avatar"},
* maxSizeMessage = "Ce fichier est trop volumineux (maximum à {{ limit }}Mo)"
* )
*
* @var File
*/
protected $avatarFile;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @var string
*/
protected $avatar;
/**
* @ORM\Column(type="string")
*/
protected $vehicleListType;
/**
* @ORM\Column(type="string")
*
* @var string
*/
protected $origin;
/**
* @ORM\OneToMany(targetEntity="VehicleAlert", mappedBy="user", cascade={"persist", "remove"})
*/
private $vehicleAlerts;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Selection", mappedBy="user", cascade={"persist", "remove"})
**/
private $selections;
/**
* @ORM\OneToMany(targetEntity="App\Entity\SmsAlert", mappedBy="user", cascade={"persist", "remove"})
**/
private $smsAlerts;
/**
* @ORM\OneToMany(targetEntity="Alert", mappedBy="user", cascade={"persist", "remove"})
*/
private $alerts;
/**
* @ORM\OneToMany(targetEntity="ProUser", mappedBy="salesman")
*/
private $managedUsers;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Transaction", mappedBy="user")
*
* @ORM\OrderBy({"createdAt"="DESC","id"="DESC"})
*/
private $transactions;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PurchaseInstruction", mappedBy="user", cascade={"remove"})
*/
private $purchaseInstructions;
/**
* @ORM\OneToMany(targetEntity="App\Entity\PurchaseInstructionRule", mappedBy="user", cascade={"remove"})
*/
private $purchaseInstructionRules;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Bid", mappedBy="user")
*/
private $bids;
/**
* @ORM\Column(type="string", length=40, unique=true)
*/
private $liveApiKey;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $liveLoggedInAt;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $liveLoggedOutAt;
/**
* Salesforce Account Id.
*
* @ORM\Column(type="string", length=18, nullable=true)
*/
private $sfAccountId;
/**
* Salesforce Contact Id.
*
* @ORM\Column(type="string", length=18, nullable=true)
*/
private $sfContactId;
/**
* @ORM\Column(type="string", length=18, nullable=true)
*/
private $sfLeadId;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\BuyersGroup", mappedBy="users", cascade={"persist"})
*/
private $buyersGroups;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Behaviour", mappedBy="user", cascade={"remove"})
*/
private $behaviours;
/**
* @ORM\Column(unique=true, nullable=true)
*/
private $adId;
/**
* @ORM\OneToMany(targetEntity="App\Entity\CgvUserSignature", mappedBy="user", cascade={"remove"})
*/
private $cgvSignatures;
public function __construct()
{
parent::__construct();
$this->locked = false;
$this->bids = new ArrayCollection();
$this->vehicleAlerts = new ArrayCollection();
$this->alerts = new ArrayCollection();
$this->transactions = new ArrayCollection();
$this->managedUsers = new ArrayCollection();
$this->auctions = new ArrayCollection();
$this->purchaseInstructions = new ArrayCollection();
$this->buyersGroups = new ArrayCollection();
$this->behaviours = new ArrayCollection();
$this->selections = new ArrayCollection();
$this->smsAlerts = new ArrayCollection();
$this->country = 'FR';
$this->smsOptin = false;
$this->liveApiKey = sha1(\random_bytes(40));
$this->language = 'fr';
$this->lastOptinChangeDate = new \DateTime();
$this->vehicleListType = 'Mosaique';
$this->society = false;
$this->origin = self::ORIGIN_VPAUTO;
}
public function getId()
{
return $this->id;
}
public function setTitle($title): void
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setLastname($lastname): void
{
$this->lastname = $lastname;
}
public function getLastname()
{
return $this->lastname;
}
public function setFirstname($firstname): void
{
$this->firstname = $firstname;
}
public function getFirstname()
{
return $this->firstname;
}
public function setAddress($address): void
{
$this->address = $address;
}
public function getAddress()
{
return $this->address;
}
public function setAddressComplement($addressComplement): void
{
$this->addressComplement = $addressComplement;
}
public function getAddressComplement()
{
return $this->addressComplement;
}
public function setZipCode($zipCode): void
{
$this->zipCode = $zipCode;
}
public function getZipCode()
{
return $this->zipCode;
}
public function setCity($city): void
{
$this->city = $city;
}
public function getCity()
{
return $this->city;
}
public function setCountry($country): void
{
$this->country = $country;
}
public function getCountry()
{
return $this->country;
}
public function getFullCountryName()
{
if (null === $this->country) {
return '';
}
try {
$country = Countries::getName($this->country);
} catch (MissingResourceException) {
$country = $this->country;
}
return $country;
}
public function setReferralSource($referralSource)
{
return $this->referralSource = $referralSource;
}
public function getReferralSource()
{
return $this->referralSource;
}
public function setPhone($phone): void
{
$this->phone = $phone;
}
public function getPhone()
{
return $this->phone;
}
public function setMobile($mobile): void
{
$this->mobile = preg_replace('/[^0-9+]/', '', $mobile);
}
public function getMobile()
{
return $this->mobile;
}
public function setCreatedAt($createdAt): void
{
$this->createdAt = $createdAt;
}
public function getCreatedAt()
{
return $this->createdAt;
}
public function setSalt($salt): void
{
$this->salt = $salt;
}
public function getSalt(): ?string
{
return $this->salt;
}
public function setUpdatedAt($updatedAt): void
{
$this->updatedAt = $updatedAt;
}
public function getUpdatedAt()
{
return $this->updatedAt;
}
public function setNewsletter($newsletter): void
{
if ($newsletter !== $this->newsletter) {
$this->lastOptinChangeDate = new \DateTime();
}
$this->newsletter = $newsletter;
}
public function getLastOptinChangeDate()
{
return $this->lastOptinChangeDate;
}
public function getNewsletter()
{
return $this->newsletter;
}
public function setSfAccountId($sfAccountId): void
{
$this->sfAccountId = $sfAccountId;
}
public function getSfAccountId()
{
return $this->sfAccountId;
}
public function setSfContactId($sfContactId): void
{
$this->sfContactId = $sfContactId;
}
public function getSfContactId()
{
return $this->sfContactId;
}
public function setSfLeadId($sfLeadId): void
{
$this->sfLeadId = $sfLeadId;
}
public function getSfLeadId()
{
return $this->sfLeadId;
}
public function addAlertOnVehicle(Vehicle $vehicle): void
{
$vehicleAlert = new VehicleAlert($vehicle);
$this->vehicleAlerts[] = $vehicleAlert;
$vehicleAlert->setUser($this);
}
public function getVehicleAlerts()
{
return $this->vehicleAlerts;
}
public function hasVehicleAlertOnVehicle(Vehicle $vehicle)
{
$criteria = Criteria::create();
$criteria
->where(
Criteria::expr()->eq('vehicle', $vehicle)
)
;
return count($this->getVehicleAlerts()->matching($criteria)) > 0;
}
public function addAlert(Alert $alerts): void
{
$this->alerts[] = $alerts;
}
public function getAlerts()
{
return $this->alerts;
}
public function setEmail($email): void
{
$this->email = $email;
$this->setUsername($email);
}
public function getAuctions()
{
return $this->auctions;
}
public function setAuctions($auctions): void
{
$this->auctions = $auctions;
}
public function addVehicleAlert(VehicleAlert $vehicleAlerts): void
{
$this->vehicleAlerts[] = $vehicleAlerts;
}
public function addTransaction(Transaction $transaction): void
{
$this->transactions[] = $transaction;
}
/**
* This is the same check that in findValidTransactionByUserAndSale,
* but it is less strict since we don't want to hide a transaction that was valid
* during the sale but expired just after.
* The threshold is 14 days => 7 days added to the 7 days base threshold.
*
* @see TransactionRepository::findValidTransactionByUserAndSale()
*/
public function getSaleTransaction(Sale $sale)
{
$validityThreshold = (new \DateTime('now'))->sub(new \DateInterval('P14D'));
return $this
->transactions
->filter(fn ($transaction) =>
/* @var Transaction $transaction */
$transaction->getSale() === $sale
&& $transaction->isValid()
&& $transaction->getCreatedAt() >= $validityThreshold)
->first()
;
}
public function getTransactions()
{
return $this->transactions;
}
public function addPurchaseInstruction(PurchaseInstruction $purchaseInstruction): void
{
$this->purchaseInstructions[] = $purchaseInstruction;
}
public function getPurchaseInstructions()
{
return $this->purchaseInstructions;
}
public function getPurchaseInstructionRules()
{
return $this->purchaseInstructionRules;
}
public function getBids()
{
return $this->bids;
}
public function getSalePurchaseInstructionRule(Sale $sale)
{
return $this
->purchaseInstructionRules
->filter(fn ($purchaseInstructionRule) => $purchaseInstructionRule->getSale() === $sale)
->first()
;
}
public function getFullName()
{
return sprintf('%s %s', $this->firstname, $this->lastname);
}
public function setLiveApiKey($liveApiKey): void
{
$this->liveApiKey = $liveApiKey;
}
public function getLiveApiKey()
{
return $this->liveApiKey;
}
public function setLiveLoggedInAt($liveLoggedInAt): void
{
$this->liveLoggedInAt = $liveLoggedInAt;
}
public function getLiveLoggedInAt()
{
return $this->liveLoggedInAt;
}
public function setLiveLoggedOutAt($liveLoggedOutAt): void
{
$this->liveLoggedOutAt = $liveLoggedOutAt;
}
public function getLiveLoggedOutAt()
{
return $this->liveLoggedOutAt;
}
public function setNeedsTransaction($needsTransaction): void
{
$this->needsTransaction = $needsTransaction;
}
public function hasNeedsTransaction()
{
return $this->needsTransaction;
}
public function setSociety($society): void
{
$this->society = $society;
}
public function isSociety()
{
return (bool) $this->society;
}
public function setSmsOptin($smsOptin): void
{
$this->smsOptin = $smsOptin;
}
public function isSmsOptin()
{
return (bool) $this->smsOptin;
}
public function setLanguage($language): void
{
$this->language = $language;
}
public function getLanguage()
{
return $this->language;
}
/**
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile $avatar
*
* @throws \Exception
*/
public function setAvatarFile(?File $avatar = null): void
{
$this->avatarFile = $avatar;
if (null !== $avatar) {
$this->updatedAt = new \DateTimeImmutable();
}
}
public function getAvatarFile()
{
return $this->avatarFile;
}
public function setAvatar($avatar): void
{
$this->avatar = $avatar;
}
public function getAvatar()
{
return $this->avatar;
}
public function setVehicleListType($vehicleListType): void
{
$this->vehicleListType = $vehicleListType;
}
public function getVehicleListType()
{
return $this->vehicleListType;
}
/**
* Checks if user has a buyersGroup.
*
* @return bool
*/
public function hasBuyersGroup(BuyersGroup $group)
{
return $this->buyersGroups->contains($group);
}
/**
* Add this user to a buyer group.
*
* @param BuyersGroup $group The group you want the user to be added to
*/
public function addBuyersGroup(BuyersGroup $group): void
{
if (!$this->hasBuyersGroup($group)) {
$this->buyersGroups[] = $group;
}
}
public function removeBuyersGroup(BuyersGroup $group): void
{
if ($this->hasBuyersGroup($group)) {
$this->buyersGroups->removeElement($group);
}
}
/**
* Get the current buyers groups the user is part of.
*
* @return ArrayCollection Contains a list of BuyersGroup objects
*/
public function getBuyersGroups()
{
return $this->buyersGroups;
}
public function addManagedUser(User $user): void
{
$this->managedUsers[] = $user;
}
public function removeManagedUser(User $user): void
{
$this->managedUsers->remove($user);
}
public function getManagedUsers()
{
return $this->managedUsers;
}
public function addBehaviour(Behaviour $behaviour): void
{
$this->behaviours[] = $behaviour;
}
public function getBehaviours()
{
return $this->behaviours;
}
public function hasAccessedSale(Sale $sale)
{
foreach ($this->getBehaviours() as $behaviour) {
if ($behaviour instanceof SaleBehaviour && $sale === $behaviour->getSale()) {
return true;
}
}
return false;
}
public function addSelection(Vehicle $vehicle): void
{
$selection = new Selection($vehicle);
$this->selections[] = $selection;
$selection->setUser($this);
}
public function getSelections()
{
$activeSelections = $this->selections->filter(fn ($selection) => $selection->getvehicle()->getSale()->getAfterSaleEndDate() > new \DateTime());
return $activeSelections;
}
public function addSmsAlert(Vehicle $vehicle): void
{
$smsAlert = new SmsAlert($vehicle);
$this->smsAlerts[] = $smsAlert;
$smsAlert->setUser($this);
}
public function getSmsAlerts()
{
$activeAlerts = $this->smsAlerts->filter(fn ($smsAlert) => $smsAlert->getVehicle()->getAuction()->getClosedAt() > new \DateTime());
return $activeAlerts;
}
public function isGranted($role)
{
return in_array($role, $this->getRoles());
}
public function isForeigner()
{
return 'FR' !== $this->country;
}
public function isLocked()
{
return !$this->isAccountNonLocked();
}
public function setLocked($boolean)
{
$this->locked = $boolean;
return $this;
}
public function isAccountNonLocked()
{
return !$this->locked;
}
/**
* Return the number of vehicle that the user is purchasing (Electronic sale or live sale).
*
* @return int
*/
public function countLiveBids()
{
$liveBids = 0;
foreach ($this->purchaseInstructions as $pi) {
if ($pi->getSale()->isActive()) {
++$liveBids;
}
}
foreach ($this->bids as $bid) {
if ($bid->getAuction()->isOpen()) {
++$liveBids;
}
}
return $liveBids;
}
public function isOnlooker()
{
return false;
}
/**
* @return string
*/
public function getOrigin()
{
return $this->origin;
}
/**
* @param string $origin
*/
public function setOrigin($origin): void
{
$this->origin = $origin;
}
public function getCgvSignatures()
{
return $this->cgvSignatures;
}
public function setCgvSignatures($cgvSignatures): void
{
$this->cgvSignatures = $cgvSignatures;
}
/**
* @return string
*/
public function getAdId()
{
return $this->adId;
}
/**
* @return $this
*/
public function setAdId(?string $adId)
{
$this->adId = $adId;
return $this;
}
}