mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 09:18:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			617 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			617 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| declare(strict_types=1);
 | |
| 
 | |
| /*
 | |
|  * Chill is a software for social workers
 | |
|  *
 | |
|  * For the full copyright and license information, please view
 | |
|  * the LICENSE file that was distributed with this source code.
 | |
|  */
 | |
| 
 | |
| namespace Chill\MainBundle\Entity;
 | |
| 
 | |
| use Chill\MainBundle\Entity\User\UserJobHistory;
 | |
| use Chill\MainBundle\Entity\User\UserScopeHistory;
 | |
| use Doctrine\Common\Collections\ArrayCollection;
 | |
| use Doctrine\Common\Collections\Collection;
 | |
| use Doctrine\Common\Collections\Criteria;
 | |
| use Doctrine\Common\Collections\Selectable;
 | |
| use Doctrine\ORM\Mapping as ORM;
 | |
| use libphonenumber\PhoneNumber;
 | |
| use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
 | |
| use Symfony\Component\Security\Core\User\UserInterface;
 | |
| use Symfony\Component\Serializer\Annotation as Serializer;
 | |
| use Symfony\Component\Validator\Context\ExecutionContextInterface;
 | |
| use Chill\MainBundle\Validation\Constraint\PhonenumberConstraint;
 | |
| 
 | |
| /**
 | |
|  * User.
 | |
|  */
 | |
| #[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['user' => User::class])]
 | |
| #[ORM\Entity]
 | |
| #[ORM\Cache(usage: 'NONSTRICT_READ_WRITE', region: 'acl_cache_region')]
 | |
| #[ORM\Table(name: 'users')]
 | |
| class User implements UserInterface, \Stringable, PasswordAuthenticatedUserInterface
 | |
| {
 | |
|     #[ORM\Id]
 | |
|     #[ORM\Column(name: 'id', type: \Doctrine\DBAL\Types\Types::INTEGER)]
 | |
|     #[ORM\GeneratedValue(strategy: 'AUTO')]
 | |
|     protected ?int $id = null;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true)]
 | |
|     private ?\DateTimeImmutable $absenceStart = null;
 | |
| 
 | |
|     /**
 | |
|      * Array where SAML attributes's data are stored.
 | |
|      */
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::JSON, nullable: false)]
 | |
|     private array $attributes = [];
 | |
| 
 | |
|     #[ORM\ManyToOne(targetEntity: Civility::class)]
 | |
|     private ?Civility $civility = null;
 | |
| 
 | |
|     #[ORM\ManyToOne(targetEntity: Location::class)]
 | |
|     private ?Location $currentLocation = null;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 150, nullable: true)]
 | |
|     private ?string $email = null;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 150, nullable: true, unique: true)]
 | |
|     private ?string $emailCanonical = null;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
 | |
|     private bool $enabled = true;
 | |
| 
 | |
|     /**
 | |
|      * @var Collection<int, GroupCenter>
 | |
|      */
 | |
|     #[ORM\ManyToMany(targetEntity: GroupCenter::class, inversedBy: 'users')]
 | |
|     #[ORM\Cache(usage: 'NONSTRICT_READ_WRITE')]
 | |
|     private Collection $groupCenters;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 200)]
 | |
|     private string $label = '';
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)] // sf4 check: in yml was false by default !?
 | |
|     private bool $locked = true;
 | |
| 
 | |
|     #[ORM\ManyToOne(targetEntity: Center::class)]
 | |
|     private ?Center $mainCenter = null;
 | |
| 
 | |
|     #[ORM\ManyToOne(targetEntity: Location::class)]
 | |
|     private ?Location $mainLocation = null;
 | |
| 
 | |
|     /**
 | |
|      * @var Collection<int, UserScopeHistory>&Selectable
 | |
|      */
 | |
|     #[ORM\OneToMany(mappedBy: 'user', targetEntity: UserScopeHistory::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
 | |
|     private Collection&Selectable $scopeHistories;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
 | |
|     private string $password = '';
 | |
| 
 | |
|     /**
 | |
|      * @internal must be set to null if we use bcrypt
 | |
|      */
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255, nullable: true)]
 | |
|     private ?string $salt = null;
 | |
| 
 | |
|     /**
 | |
|      * @var Collection<int, UserJobHistory>&Selectable
 | |
|      */
 | |
|     #[ORM\OneToMany(mappedBy: 'user', targetEntity: UserJobHistory::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
 | |
|     private Collection&Selectable $jobHistories;
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 80)]
 | |
|     private string $username = '';
 | |
| 
 | |
|     #[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 80, unique: true, nullable: true)]
 | |
|     private ?string $usernameCanonical = null;
 | |
| 
 | |
|     /**
 | |
|      * The user's mobile phone number.
 | |
|      */
 | |
|     #[ORM\Column(type: 'phone_number', nullable: true)]
 | |
|     #[PhonenumberConstraint]
 | |
|     private ?PhoneNumber $phonenumber = null;
 | |
| 
 | |
|     /**
 | |
|      * User constructor.
 | |
|      */
 | |
|     public function __construct()
 | |
|     {
 | |
|         $this->groupCenters = new ArrayCollection();
 | |
|         $this->scopeHistories = new ArrayCollection();
 | |
|         $this->jobHistories = new ArrayCollection();
 | |
|     }
 | |
| 
 | |
|     public function __toString(): string
 | |
|     {
 | |
|         return $this->getLabel();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return User
 | |
|      */
 | |
|     public function addGroupCenter(GroupCenter $groupCenter)
 | |
|     {
 | |
|         $this->groupCenters->add($groupCenter);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function eraseCredentials() {}
 | |
| 
 | |
|     public function getAbsenceStart(): ?\DateTimeImmutable
 | |
|     {
 | |
|         return $this->absenceStart;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get attributes.
 | |
|      *
 | |
|      * @return array
 | |
|      */
 | |
|     public function getAttributes()
 | |
|     {
 | |
|         if (null === $this->attributes) {
 | |
|             $this->attributes = [];
 | |
|         }
 | |
| 
 | |
|         return $this->attributes;
 | |
|     }
 | |
| 
 | |
|     public function getCivility(): ?Civility
 | |
|     {
 | |
|         return $this->civility;
 | |
|     }
 | |
| 
 | |
|     public function getCurrentLocation(): ?Location
 | |
|     {
 | |
|         return $this->currentLocation;
 | |
|     }
 | |
| 
 | |
|     public function getEmail(): ?string
 | |
|     {
 | |
|         return $this->email;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function getEmailCanonical()
 | |
|     {
 | |
|         return $this->emailCanonical;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return Collection<GroupCenter>
 | |
|      */
 | |
|     public function getGroupCenters(): Collection
 | |
|     {
 | |
|         return $this->groupCenters;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get id.
 | |
|      */
 | |
|     public function getId(): ?int
 | |
|     {
 | |
|         return $this->id;
 | |
|     }
 | |
| 
 | |
|     public function getLabel(): string
 | |
|     {
 | |
|         return $this->label;
 | |
|     }
 | |
| 
 | |
|     public function getMainCenter(): ?Center
 | |
|     {
 | |
|         return $this->mainCenter;
 | |
|     }
 | |
| 
 | |
|     public function getMainLocation(): ?Location
 | |
|     {
 | |
|         return $this->mainLocation;
 | |
|     }
 | |
| 
 | |
|     public function getMainScope(?\DateTimeImmutable $atDate = null): ?Scope
 | |
|     {
 | |
|         $atDate ??= new \DateTimeImmutable('now');
 | |
| 
 | |
|         foreach ($this->scopeHistories as $scopeHistory) {
 | |
|             if ($atDate >= $scopeHistory->getStartDate() && (
 | |
|                 null === $scopeHistory->getEndDate() || $atDate < $scopeHistory->getEndDate()
 | |
|             )) {
 | |
|                 return $scopeHistory->getScope();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
|     public function getMainScopeHistories(): Collection
 | |
|     {
 | |
|         return $this->scopeHistories;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return ArrayCollection|UserScopeHistory[]
 | |
|      */
 | |
|     public function getMainScopeHistoriesOrdered(): ArrayCollection
 | |
|     {
 | |
|         $scopeHistories = $this->getMainScopeHistories();
 | |
| 
 | |
|         $sortedScopeHistories = $scopeHistories->toArray();
 | |
| 
 | |
|         usort($sortedScopeHistories, fn ($a, $b) => $a->getStartDate() < $b->getStartDate() ? 1 : -1);
 | |
| 
 | |
|         return new ArrayCollection($sortedScopeHistories);
 | |
|     }
 | |
| 
 | |
|     public function getPassword(): ?string
 | |
|     {
 | |
|         return $this->password;
 | |
|     }
 | |
| 
 | |
|     public function getRoles(): array
 | |
|     {
 | |
|         return ['ROLE_USER'];
 | |
|     }
 | |
| 
 | |
|     public function getSalt(): ?string
 | |
|     {
 | |
|         return $this->salt;
 | |
|     }
 | |
| 
 | |
|     public function getUserJob(?\DateTimeImmutable $atDate = null): ?UserJob
 | |
|     {
 | |
|         $atDate ??= new \DateTimeImmutable('now');
 | |
| 
 | |
|         foreach ($this->jobHistories as $jobHistory) {
 | |
|             if ($atDate >= $jobHistory->getStartDate() && (
 | |
|                 null === $jobHistory->getEndDate() || $atDate < $jobHistory->getEndDate()
 | |
|             )) {
 | |
|                 return $jobHistory->getJob();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
|     public function getUserJobHistories(): Collection
 | |
|     {
 | |
|         return $this->jobHistories;
 | |
|     }
 | |
| 
 | |
|     public function getUserScopeHistories(): Collection
 | |
|     {
 | |
|         return $this->scopeHistories;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return ArrayCollection|UserJobHistory[]
 | |
|      */
 | |
|     public function getUserJobHistoriesOrdered(): ArrayCollection
 | |
|     {
 | |
|         $jobHistories = $this->getUserJobHistories();
 | |
| 
 | |
|         $sortedJobHistories = $jobHistories->toArray();
 | |
| 
 | |
|         usort($sortedJobHistories, fn ($a, $b) => $a->getStartDate() < $b->getStartDate() ? 1 : -1);
 | |
| 
 | |
|         return new ArrayCollection($sortedJobHistories);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function getUsername()
 | |
|     {
 | |
|         return $this->username;
 | |
|     }
 | |
| 
 | |
|     public function getUserIdentifier(): string
 | |
|     {
 | |
|         return $this->username;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return string
 | |
|      */
 | |
|     public function getUsernameCanonical()
 | |
|     {
 | |
|         return $this->usernameCanonical;
 | |
|     }
 | |
| 
 | |
|     public function isAbsent(): bool
 | |
|     {
 | |
|         return null !== $this->getAbsenceStart() && $this->getAbsenceStart() <= new \DateTimeImmutable('now');
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isAccountNonExpired()
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isAccountNonLocked()
 | |
|     {
 | |
|         return $this->locked;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isCredentialsNonExpired()
 | |
|     {
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return bool
 | |
|      */
 | |
|     public function isEnabled()
 | |
|     {
 | |
|         return $this->enabled;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * This function check that groupCenter are present only once. The validator
 | |
|      * use this function to avoid a user to be associated to the same groupCenter
 | |
|      * more than once.
 | |
|      */
 | |
|     public function isGroupCenterPresentOnce(ExecutionContextInterface $context)
 | |
|     {
 | |
|         $groupCentersIds = [];
 | |
| 
 | |
|         foreach ($this->getGroupCenters() as $groupCenter) {
 | |
|             if (\in_array($groupCenter->getId(), $groupCentersIds, true)) {
 | |
|                 $context->buildViolation('The user has already those permissions')
 | |
|                     ->addViolation();
 | |
|             } else {
 | |
|                 $groupCentersIds[] = $groupCenter->getId();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function getPhonenumber(): ?PhoneNumber
 | |
|     {
 | |
|         return $this->phonenumber;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @throws \RuntimeException if the groupCenter is not in the collection
 | |
|      */
 | |
|     public function removeGroupCenter(GroupCenter $groupCenter)
 | |
|     {
 | |
|         if (false === $this->groupCenters->removeElement($groupCenter)) {
 | |
|             throw new \RuntimeException('The groupCenter could not be removed, it seems not to be associated with the user. Aborting.');
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public function setAbsenceStart(?\DateTimeImmutable $absenceStart): void
 | |
|     {
 | |
|         $this->absenceStart = $absenceStart;
 | |
|     }
 | |
| 
 | |
|     public function setAttributeByDomain(string $domain, string $key, $value): self
 | |
|     {
 | |
|         $this->attributes[$domain][$key] = $value;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Merge the attributes with existing attributes.
 | |
|      *
 | |
|      * Only the key provided will be created or updated. For a two-level array, use @see{User::setAttributeByDomain}
 | |
|      */
 | |
|     public function setAttributes(array $attributes): self
 | |
|     {
 | |
|         $this->attributes = array_merge($this->attributes, $attributes);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setCivility(?Civility $civility): User
 | |
|     {
 | |
|         $this->civility = $civility;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setCurrentLocation(?Location $currentLocation): User
 | |
|     {
 | |
|         $this->currentLocation = $currentLocation;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setEmail(?string $email)
 | |
|     {
 | |
|         $this->email = $email;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setEmailCanonical(?string $emailCanonical)
 | |
|     {
 | |
|         $this->emailCanonical = $emailCanonical;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setEnabled(bool $enabled)
 | |
|     {
 | |
|         $this->enabled = $enabled;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setLabel(string $label): User
 | |
|     {
 | |
|         $this->label = $label;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setMainCenter(?Center $mainCenter): User
 | |
|     {
 | |
|         $this->mainCenter = $mainCenter;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setMainLocation(?Location $mainLocation): User
 | |
|     {
 | |
|         $this->mainLocation = $mainLocation;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setMainScope(?Scope $mainScope): User
 | |
|     {
 | |
|         if ($mainScope === $this->getMainScope()) {
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         $newScope = new UserScopeHistory();
 | |
| 
 | |
|         $newScope
 | |
|             ->setStartDate(new \DateTimeImmutable('now'))
 | |
|             ->setScope($mainScope)
 | |
|             ->setUser($this);
 | |
| 
 | |
|         $this->scopeHistories[] = $newScope;
 | |
| 
 | |
|         $criteria = new Criteria();
 | |
|         $criteria->orderBy(['startDate' => 'ASC', 'id' => 'ASC']);
 | |
| 
 | |
|         /** @var \Iterator $scopes */
 | |
|         $scopes = $this->scopeHistories->matching($criteria)->getIterator();
 | |
|         $scopes->rewind();
 | |
| 
 | |
|         do {
 | |
|             /** @var UserScopeHistory $current */
 | |
|             $current = $scopes->current();
 | |
|             $scopes->next();
 | |
| 
 | |
|             if ($scopes->valid()) {
 | |
|                 $next = $scopes->current();
 | |
|                 $current->setEndDate($next->getStartDate());
 | |
|             }
 | |
|         } while ($scopes->valid());
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setPassword(string $password)
 | |
|     {
 | |
|         $this->password = $password;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setSalt(?string $salt)
 | |
|     {
 | |
|         $this->salt = $salt;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setUserJob(?UserJob $userJob): User
 | |
|     {
 | |
|         if ($userJob === $this->getUserJob()) {
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         $newJob = new UserJobHistory();
 | |
| 
 | |
|         $newJob
 | |
|             ->setStartDate(new \DateTimeImmutable('now'))
 | |
|             ->setJob($userJob)
 | |
|             ->setUser($this);
 | |
| 
 | |
|         $this->jobHistories[] = $newJob;
 | |
| 
 | |
|         $criteria = new Criteria();
 | |
|         $criteria->orderBy(['startDate' => \Doctrine\Common\Collections\Order::Ascending, 'id' => \Doctrine\Common\Collections\Order::Ascending]);
 | |
| 
 | |
|         /** @var \Iterator $jobs */
 | |
|         $jobs = $this->jobHistories->matching($criteria)->getIterator();
 | |
|         $jobs->rewind();
 | |
| 
 | |
|         do {
 | |
|             /** @var UserJobHistory $current */
 | |
|             $current = $jobs->current();
 | |
|             $jobs->next();
 | |
| 
 | |
|             if ($jobs->valid()) {
 | |
|                 $next = $jobs->current();
 | |
|                 $current->setEndDate($next->getStartDate());
 | |
|             }
 | |
|         } while ($jobs->valid());
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set username.
 | |
|      *
 | |
|      * @return User
 | |
|      */
 | |
|     public function setUsername(?string $name)
 | |
|     {
 | |
|         $this->username = (string) $name;
 | |
| 
 | |
|         if ('' === trim($this->getLabel())) {
 | |
|             $this->setLabel($name);
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setUsernameCanonical(?string $usernameCanonical)
 | |
|     {
 | |
|         $this->usernameCanonical = $usernameCanonical;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function unsetAttribute($key): self
 | |
|     {
 | |
|         unset($this->attributes[$key]);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     public function setPhonenumber(?PhoneNumber $phonenumber): self
 | |
|     {
 | |
|         $this->phonenumber = $phonenumber;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| }
 |