<?php
namespace App\Entity;
use App\Service\CpfValidator;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Ramsey\Uuid\Uuid;
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;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @ORM\Entity(repositoryClass="App\Repository\UsuarioRepository")
* @UniqueEntity(
* fields={"email"},
* message="Este email já está cadastrado no sistema."
* )
*/
class Usuario implements UserInterface, PasswordAuthenticatedUserInterface
{
use TimestampableEntity;
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private ?int $id=null;
/**
* @ORM\Column(type="string", length=191, unique=true)
* @Assert\Length(max=191)
*/
private string $email;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Length(max=255)
*/
private ?string $password=null;
/**
* A non-persisted field that's used to create the encoded password.
*/
private ?string $plainPassword=null;
/**
* @ORM\Column(type="json")
*/
protected array $roles = ['ROLE_USER'];
/**
* @ORM\Column(type="string", length=255)
*/
private string $nome;
/**
* @ORM\Column(type="boolean")
*/
private bool $ativo = true;
/**
* @var ?string Reset token.
*
* @ORM\Column(name="reset_token", type="string", length=32, nullable=true)
* @Assert\Length(max=32)
*/
private ?string $resetToken=null;
/**
* @var ?int Unix Epoch timestamp when the reset token expires.
*
* @ORM\Column(name="reset_token_expires_at", type="integer", nullable=true)
*/
private ?int $resetTokenExpiresAt=null;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Arquivo", mappedBy="usuario")
*/
private Collection $arquivos;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Permissao", mappedBy="professor")
*/
private Collection $permissoes;
/**
* @ORM\Column(type="string", length=255, nullable=false)
* @Assert\Length(max=255)
*/
private string $nacionalidade = 'BR';
/**
* @ORM\Column(type="string", length=15, unique=true, nullable=true)
* @Assert\Length(max=15)
*/
private ?string $cpf=null;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Inscricao", mappedBy="candidato")
*/
private Collection $inscricoes;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\Length(max=255)
*/
private ?string $resetEmail=null;
/**
* @ORM\Column(type="string", length=20, nullable=true)
* @Assert\Length(max=20)
*/
private ?string $telefone=null;
/**
* @ORM\Column(type="string", length=25, nullable=true)
* @Assert\Length(max=25)
*/
private ?string $passaporte=null;
/**
* @ORM\OneToMany(targetEntity="App\Entity\RemanejoInscricao", mappedBy="solicitante")
*/
private Collection $remanejos;
/**
* @ORM\OneToMany(targetEntity="App\Entity\RemanejoInscricao", mappedBy="responsavel")
*/
private Collection $remanejosAceitos;
/**
* @ORM\OneToMany(targetEntity="App\Entity\RecursoInscricao", mappedBy="responsavel")
*/
private Collection $recursos;
public function __construct()
{
$this->arquivos = new ArrayCollection();
$this->permissoes = new ArrayCollection();
$this->inscricoes = new ArrayCollection();
$this->remanejos = new ArrayCollection();
$this->remanejosAceitos = new ArrayCollection();
$this->recursos = new ArrayCollection();
}
public function __toString(): string
{
return $this->nome;
}
/**
* @return string Versão obfuscada do e-mail (ex: s******a@n******s.com.br)
*/
public function getObfuscatedEmail(): string
{
$email = $this->getEmail();
$parts = explode('@', $email);
foreach ($parts as $p => $v) {
$subparts = explode('.', $v);
foreach ($subparts as $i => $s) {
if (strlen($s) > 3) {
$subparts[$i] = substr($s, 0, 1) . str_repeat('*', strlen($s)-2) . substr($s, strlen($s)-1, 1);
}
elseif ($p == 0) {
// ofusca o username, mesmo se for curtinho
$subparts[$i] = str_repeat('*', strlen($s));
}
}
$parts[$p] = implode('.', $subparts);
}
return implode('@', $parts);
}
public function getFirstName(): string
{
$name = explode(' ', $this->getNome());
return mb_convert_case($name[0], MB_CASE_TITLE);
}
public function isAdmin(): bool
{
return in_array('ROLE_ADMIN', $this->roles);
}
public function isProfessor(): bool
{
return in_array('ROLE_PROFESSOR', $this->roles) || in_array('ROLE_PROFESSOR_INATIVO', $this->roles);
}
public function isFuncionario(): bool
{
return in_array('ROLE_FUNCIONARIO', $this->roles) || in_array('ROLE_FUNCIONARIO_INATIVO', $this->roles);
}
public function isCandidato(): bool
{
return in_array('ROLE_CANDIDATO', $this->roles) || in_array('ROLE_CANDIDATO_BLOQUEADO', $this->roles);
}
/**
* @return string Descrição do nível mais alto das funções do usuário
*/
public function getTipo(): string
{
$tipo = "Usuário";
if ($this->isAdmin()) {
$tipo = "Administrador";
}
elseif ($this->isFuncionario()) {
$tipo = "Funcionário";
}
elseif ($this->isProfessor()) {
$tipo = "Professor";
}
elseif ($this->isCandidato()) {
$tipo = "Candidato";
}
return $tipo;
}
/**
* @return string Uma senha forte aleatória
*/
static public function generatePassword(): string {
$pass = '';
$points = '#@!.;,/=-+*&%[]{}?:<>()_';
$checks = ['lower' => false, 'upper' => false, 'digit' => false, 'point' => false];
do {
$lower = chr(rand(ord('a'), ord('z')));
$upper = chr(rand(ord('A'), ord('Z')));
$digit = chr(rand(ord('0'), ord('9')));
$point = substr($points, rand(0, strlen($points)-1), 1);
$surprise = rand(0,100);
if ($surprise < 60) {
if ($surprise < 40) {
$pass .= $lower;
$checks['lower'] = true;
}
else {
$pass .= $upper;
$checks['upper'] = true;
}
}
elseif ($surprise < 90) {
$pass .= $digit;
$checks['digit'] = true;
}
else {
$pass .= $point;
$checks['point'] = true;
}
} while (strlen($pass) < 10);
if (!$checks['lower']) {
$p = rand(0, strlen($pass));
$lower = chr(rand(ord('a'), ord('z')));
$pass = substr($pass, 0, $p) . $lower . substr($pass, $p);
}
if (!$checks['upper']) {
$p = rand(0, strlen($pass));
$upper = chr(rand(ord('A'), ord('Z')));
$pass = substr($pass, 0, $p) . $lower . substr($pass, $p);
}
if (!$checks['digit']) {
$p = rand(0, strlen($pass));
$digit = chr(rand(ord('0'), ord('9')));
$pass = substr($pass, 0, $p) . $digit . substr($pass, $p);
}
if (!$checks['point']) {
$p = rand(0, strlen($pass));
$point = substr($points, rand(0, strlen($points)-1), 1);
$pass = substr($pass, 0, $p) . $point . substr($pass, $p);
}
return $pass;
}
/**---------------------ROTINAS DE SEGURANÇA------------------*/
/**
* Returns the salt that was originally used to encode the password.
*
* This can return null if the password was not encoded using a salt.
*
* @return string|null The salt
*/
public function getSalt(): ?string
{
// Not used
return null;
}
/**
* Returns the username used to authenticate the user.
*
* @return string The username
*/
public function getUsername(): string
{
return $this->email;
}
public function getUserIdentifier(): string
{
return $this->email;
}
/**
* Removes sensitive data from the user.
*
* This is important if, at any given point, sensitive information like
* the plain-text password is stored on this object.
*/
public function eraseCredentials(): void
{
$this->plainPassword = null;
}
public function getPlainPassword(): ?string
{
return $this->plainPassword;
}
public function setPlainPassword(?string $plainPassword): void
{
$this->plainPassword = $plainPassword;
// forces the object to look "dirty" to Doctrine. Avoids
// Doctrine *not* saving this entity, if only plainPassword changes
$this->password = null;
}
/**
* Generates new reset token which expires in specified period of time.
*
* @param \DateInterval $interval
*
* @return string Generated token.
*/
public function generateResetToken(\DateInterval $interval): string
{
$now = new \DateTime();
try {
$this->resetToken = Uuid::uuid4()->getHex();
} catch (\Exception $e) {
return false;
}
$this->resetTokenExpiresAt = $now->add($interval)->getTimestamp();
return $this->resetToken;
}
/**
* Generates new reset token which expires in specified period of time.
*
* @param string $email
* @param \DateInterval $interval
*
* @return string Generated token.
*/
public function generateEmailResetToken(string $email, \DateInterval $interval): string
{
$resetToken = $this->generateResetToken($interval);
if ($resetToken) {
$this->resetEmail = $email;
}
return $resetToken;
}
/**
* Clears current reset token.
*
* @return self
*/
public function clearResetToken(): self
{
$this->resetToken = null;
$this->resetTokenExpiresAt = null;
$this->resetEmail = null;
return $this;
}
/**
* Checks whether reset token is valid.
*
* @return bool
*/
public function isResetTokenValid(): bool
{
return
$this->resetTokenExpiresAt !== null &&
$this->resetEmail === null &&
$this->resetTokenExpiresAt > time();
}
/**
* Checks whether reset token is valid.
*
* @param int $userId ID do usuário logado, ou 0 para ignorar isso
* @return bool
*/
public function isEmailResetTokenValid(int $userId): bool
{
return
$this->resetTokenExpiresAt !== null &&
$this->resetEmail !== null &&
(!$userId || $userId == $this->getId()) &&
$this->resetTokenExpiresAt > time();
}
/**---------------------GETTERS E SETTERS------------------*/
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getRoles(): array
{
$roles = $this->roles;
// give everyone ROLE_USER!
if (!in_array('ROLE_USER', $roles)) {
$roles[] = 'ROLE_USER';
}
return $roles;
}
public function setRoles(array $roles): self
{
// índices não sequenciais podem afetar a formatação final no campo
$this->roles = array_values($roles);
return $this;
}
public function getNome(): string
{
return $this->nome;
}
public function setNome(string $nome): self
{
$this->nome = $nome;
return $this;
}
public function getAtivo(): bool
{
return $this->ativo;
}
public function setAtivo(bool $ativo): self
{
$this->ativo = $ativo;
return $this;
}
/**
* @return Collection|Arquivo[]
*/
public function getArquivos(): Collection
{
return $this->arquivos;
}
public function addArquivo(Arquivo $arquivo): self
{
if (!$this->arquivos->contains($arquivo)) {
$this->arquivos[] = $arquivo;
$arquivo->setUsuario($this);
}
return $this;
}
public function removeArquivo(Arquivo $arquivo): self
{
if ($this->arquivos->contains($arquivo)) {
$this->arquivos->removeElement($arquivo);
// set the owning side to null (unless already changed)
if ($arquivo->getUsuario() === $this) {
$arquivo->setUsuario(null);
}
}
return $this;
}
/**
* @return Collection|Permissao[]
*/
public function getPermissoes(): Collection
{
return $this->permissoes;
}
public function addPermissao(Permissao $permissao): self
{
if (!$this->permissoes->contains($permissao)) {
$this->permissoes[] = $permissao;
$permissao->setProfessor($this);
}
return $this;
}
public function removePermissao(Permissao $permissao): self
{
if ($this->permissoes->contains($permissao)) {
$this->permissoes->removeElement($permissao);
// set the owning side to null (unless already changed)
if ($permissao->getProfessor() === $this) {
$permissao->setProfessor(null);
}
}
return $this;
}
public function getCpf(): ?string
{
return $this->cpf;
}
public function setCpf(?string $cpf): self
{
$this->cpf = $cpf;
return $this;
}
public function getNacionalidade(): string
{
return $this->nacionalidade;
}
public function setNacionalidade(string $nacionalidade): self
{
$this->nacionalidade = $nacionalidade;
return $this;
}
/**
* @return Collection|Inscricao[]
*/
public function getInscricoes(): Collection
{
return $this->inscricoes;
}
public function addInscricao(Inscricao $inscricao): self
{
if (!$this->inscricoes->contains($inscricao)) {
$this->inscricoes[] = $inscricao;
$inscricao->setCandidato($this);
}
return $this;
}
public function removeInscricao(Inscricao $inscricao): self
{
if ($this->inscricoes->contains($inscricao)) {
$this->inscricoes->removeElement($inscricao);
// set the owning side to null (unless already changed)
if ($inscricao->getCandidato() === $this) {
$inscricao->setCandidato(null);
}
}
return $this;
}
public function getResetEmail(): ?string
{
return $this->resetEmail;
}
public function setResetEmail(?string $new_email): self
{
$this->resetEmail = $new_email;
return $this;
}
public function getTelefone(): ?string
{
return $this->telefone;
}
public function setTelefone(?string $telefone): self
{
$this->telefone = $telefone;
return $this;
}
public function getPassaporte(): ?string
{
return $this->passaporte;
}
public function setPassaporte(?string $passaporte): self
{
$this->passaporte = $passaporte;
return $this;
}
/**
* @return Collection|RemanejoInscricao[]
*/
public function getRemanejos(): Collection
{
return $this->remanejos;
}
public function addRemanejo(RemanejoInscricao $remanejo): self
{
if (!$this->remanejos->contains($remanejo)) {
$this->remanejos[] = $remanejo;
$remanejo->setSolicitante($this);
}
return $this;
}
public function removeRemanejo(RemanejoInscricao $remanejo): self
{
if ($this->remanejos->contains($remanejo)) {
$this->remanejos->removeElement($remanejo);
// set the owning side to null (unless already changed)
if ($remanejo->getSolicitante() === $this) {
$remanejo->setSolicitante(null);
}
}
return $this;
}
/**
* @return Collection|RemanejoInscricao[]
*/
public function getRemanejosAceitos(): Collection
{
return $this->remanejosAceitos;
}
public function addRemanejosAceito(RemanejoInscricao $remanejosAceito): self
{
if (!$this->remanejosAceitos->contains($remanejosAceito)) {
$this->remanejosAceitos[] = $remanejosAceito;
$remanejosAceito->setResponsavel($this);
}
return $this;
}
public function removeRemanejosAceito(RemanejoInscricao $remanejosAceito): self
{
if ($this->remanejosAceitos->contains($remanejosAceito)) {
$this->remanejosAceitos->removeElement($remanejosAceito);
// set the owning side to null (unless already changed)
if ($remanejosAceito->getResponsavel() === $this) {
$remanejosAceito->setResponsavel(null);
}
}
return $this;
}
/**
* @return Collection|RecursoInscricao[]
*/
public function getRecursos(): Collection
{
return $this->recursos;
}
public function addRecurso(RecursoInscricao $recurso): self
{
if (!$this->recursos->contains($recurso)) {
$this->recursos[] = $recurso;
$recurso->setResponsavel($this);
}
return $this;
}
public function removeRecurso(RecursoInscricao $recurso): self
{
if ($this->recursos->contains($recurso)) {
$this->recursos->removeElement($recurso);
// set the owning side to null (unless already changed)
if ($recurso->getResponsavel() === $this) {
$recurso->setResponsavel(null);
}
}
return $this;
}
}