bumped symfony to 5.3
This commit is contained in:
.env.gitignoresymfony.lock
assets
app.jsbootstrap.jscontrollers.json
composer.jsoncomposer.lockcontrollers
images
24unix
Settings
root_screen.pngroot_screen_original.pnguser_screen.pnguser_screen_original.pngvi_screen.pngvi_screen_original.png
Spookie
alien-profile.pngasteroid.jpegbg.jpegmeteor-shower.jpgjs
styles
config
bundles.php
packages
migrations
package.jsonsrc
Controller
Entity
Form
Security
templates
webpack.config.jsyarn.lock@ -22,6 +22,7 @@ class BlogCrudController extends AbstractCrudController
|
||||
AssociationField::new('author')
|
||||
->autocomplete(),
|
||||
TextField::new('title'),
|
||||
TextField::new('slug'),
|
||||
TextEditorField::new('teaser'),
|
||||
TextEditorField::new('content'),
|
||||
DateTimeField::new('createdAt'),
|
||||
|
@ -29,11 +29,11 @@ class BlogController extends AbstractController
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
#[Route('/blog/{id}', name: 'blog')]
|
||||
public function show($id, BlogRepository $blogRepository): Response
|
||||
#[Route('/blog/{slug}', name: 'blog')]
|
||||
public function show($slug, BlogRepository $blogRepository): Response
|
||||
{
|
||||
return $this->render('blog/show.html.twig', [
|
||||
'blog' => $blogRepository->findOneBy(['id' => $id])
|
||||
'blog' => $blogRepository->findOneBy(['slug' => $slug])
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
94
src/Controller/RegistrationController.php
Normal file
94
src/Controller/RegistrationController.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Form\RegistrationFormType;
|
||||
use App\Security\EmailVerifier;
|
||||
use App\Repository\UserRepository;
|
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
|
||||
|
||||
class RegistrationController extends AbstractController
|
||||
{
|
||||
private $emailVerifier;
|
||||
|
||||
public function __construct(EmailVerifier $emailVerifier)
|
||||
{
|
||||
$this->emailVerifier = $emailVerifier;
|
||||
}
|
||||
|
||||
#[Route('/register', name: 'app_register')]
|
||||
public function register(Request $request, UserPasswordEncoderInterface $passwordEncoder): Response
|
||||
{
|
||||
$user = new User();
|
||||
$form = $this->createForm(RegistrationFormType::class, $user);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
// encode the plain password
|
||||
$user->setPassword(
|
||||
$passwordEncoder->encodePassword(
|
||||
$user,
|
||||
$form->get('plainPassword')->getData()
|
||||
)
|
||||
);
|
||||
|
||||
$entityManager = $this->getDoctrine()->getManager();
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
// generate a signed url and email it to the user
|
||||
$this->emailVerifier->sendEmailConfirmation('app_verify_email', $user,
|
||||
(new TemplatedEmail())
|
||||
->from(new Address('tracer@24unix.net', '24unix'))
|
||||
->to($user->getEmail())
|
||||
->subject('Please Confirm your Email')
|
||||
->htmlTemplate('registration/confirmation_email.html.twig')
|
||||
);
|
||||
// do anything else you need here, like send an email
|
||||
|
||||
return $this->redirectToRoute('blogs');
|
||||
}
|
||||
|
||||
return $this->render('registration/register.html.twig', [
|
||||
'registrationForm' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/verify/email', name: 'app_verify_email')]
|
||||
public function verifyUserEmail(Request $request, UserRepository $userRepository): Response
|
||||
{
|
||||
$id = $request->get('id');
|
||||
|
||||
if (null === $id) {
|
||||
return $this->redirectToRoute('app_register');
|
||||
}
|
||||
|
||||
$user = $userRepository->find($id);
|
||||
|
||||
if (null === $user) {
|
||||
return $this->redirectToRoute('app_register');
|
||||
}
|
||||
|
||||
// validate email confirmation link, sets User::isVerified=true and persists
|
||||
try {
|
||||
$this->emailVerifier->handleEmailConfirmation($request, $user);
|
||||
} catch (VerifyEmailExceptionInterface $exception) {
|
||||
$this->addFlash('verify_email_error', $exception->getReason());
|
||||
|
||||
return $this->redirectToRoute('app_register');
|
||||
}
|
||||
|
||||
// @TODO Change the redirect on success and handle or remove the flash message in your templates
|
||||
$this->addFlash('success', 'Your email address has been verified.');
|
||||
|
||||
return $this->redirectToRoute('app_register');
|
||||
}
|
||||
}
|
@ -6,9 +6,12 @@ use App\Repository\BlogRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use App\Repository\SectionRepository;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=BlogRepository::class)
|
||||
* @ORM\HasLifecycleCallbacks()
|
||||
*/
|
||||
class Blog
|
||||
{
|
||||
@ -22,28 +25,28 @@ class Blog
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $title;
|
||||
private ?string $title;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=true)
|
||||
*/
|
||||
private $teaser;
|
||||
private ?string $teaser;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
*/
|
||||
private $teaserImage;
|
||||
private ?string $teaserImage;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text")
|
||||
*/
|
||||
private $content;
|
||||
private ?string $content;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="blogs")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
*/
|
||||
private $author;
|
||||
private ?User $author;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=Section::class, inversedBy="blogs")
|
||||
@ -53,17 +56,17 @@ class Blog
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
private $createdAt;
|
||||
private ?\DateTimeInterface $createdAt;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime", nullable=true)
|
||||
*/
|
||||
private $editedAt;
|
||||
private ?\DateTimeInterface $editedAt;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
*/
|
||||
private $editedBy;
|
||||
private ?User $editedBy;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
@ -75,16 +78,25 @@ class Blog
|
||||
*/
|
||||
private $comments;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
*/
|
||||
private $slug;
|
||||
|
||||
#[Pure]
|
||||
public function __construct()
|
||||
{
|
||||
$this->section = new ArrayCollection();
|
||||
$this->comments = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
|
||||
public function getId(): ?int
|
||||
@ -253,4 +265,16 @@ class Blog
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSlug(): ?string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function setSlug(string $slug): self
|
||||
{
|
||||
$this->slug = $slug;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=UserRepository::class)
|
||||
* @UniqueEntity(fields={"username"}, message="There is already an account with this username")
|
||||
*/
|
||||
class User implements UserInterface
|
||||
{
|
||||
@ -71,22 +73,27 @@ class User implements UserInterface
|
||||
* @ORM\OneToMany(targetEntity=Comment::class, mappedBy="author")
|
||||
*/
|
||||
private $comments;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
*/
|
||||
private $isVerified = false;
|
||||
|
||||
#[Pure] public function __construct()
|
||||
{
|
||||
$this->blogs = new ArrayCollection();
|
||||
$this->comments = new ArrayCollection();
|
||||
}
|
||||
{
|
||||
$this->blogs = new ArrayCollection();
|
||||
$this->comments = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* A visual identifier that represents this user.
|
||||
@ -94,50 +101,50 @@ class User implements UserInterface
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getUsername(): string
|
||||
{
|
||||
return (string)$this->username;
|
||||
}
|
||||
{
|
||||
return (string)$this->username;
|
||||
}
|
||||
|
||||
public function setUsername(string $username): self
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getRoles(): array
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
$roles[] = 'ROLE_USER';
|
||||
|
||||
return array_unique($roles);
|
||||
}
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
$roles[] = 'ROLE_USER';
|
||||
|
||||
return array_unique($roles);
|
||||
}
|
||||
|
||||
public function setRoles(array $roles): self
|
||||
{
|
||||
$this->roles = $roles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->roles = $roles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): self
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returning a salt is only needed, if you are not using a modern
|
||||
@ -146,136 +153,148 @@ class User implements UserInterface
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getSalt(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function eraseCredentials()
|
||||
{
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
{
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
|
||||
public function getFirstName(): ?string
|
||||
{
|
||||
return $this->firstName;
|
||||
}
|
||||
{
|
||||
return $this->firstName;
|
||||
}
|
||||
|
||||
public function setFirstName(?string $firstName): self
|
||||
{
|
||||
$this->firstName = $firstName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->firstName = $firstName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLastName(): ?string
|
||||
{
|
||||
return $this->lastName;
|
||||
}
|
||||
{
|
||||
return $this->lastName;
|
||||
}
|
||||
|
||||
public function setLastName(?string $lastName): self
|
||||
{
|
||||
$this->lastName = $lastName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->lastName = $lastName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): self
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function setCreatedAt(\DateTimeInterface $createdAt): self
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLastLoginAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->lastLoginAt;
|
||||
}
|
||||
{
|
||||
return $this->lastLoginAt;
|
||||
}
|
||||
|
||||
public function setLastLoginAt(?\DateTimeInterface $lastLoginAt): self
|
||||
{
|
||||
$this->lastLoginAt = $lastLoginAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
$this->lastLoginAt = $lastLoginAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Blog[]
|
||||
*/
|
||||
public function getBlogs(): Collection
|
||||
{
|
||||
return $this->blogs;
|
||||
}
|
||||
{
|
||||
return $this->blogs;
|
||||
}
|
||||
|
||||
public function addBlog(Blog $blog): self
|
||||
{
|
||||
if (!$this->blogs->contains($blog)) {
|
||||
$this->blogs[] = $blog;
|
||||
$blog->setAuthor($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
if (!$this->blogs->contains($blog)) {
|
||||
$this->blogs[] = $blog;
|
||||
$blog->setAuthor($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeBlog(Blog $blog): self
|
||||
{
|
||||
if ($this->blogs->removeElement($blog)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($blog->getAuthor() === $this) {
|
||||
$blog->setAuthor(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
if ($this->blogs->removeElement($blog)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($blog->getAuthor() === $this) {
|
||||
$blog->setAuthor(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|Comment[]
|
||||
*/
|
||||
public function getComments(): Collection
|
||||
{
|
||||
return $this->comments;
|
||||
}
|
||||
{
|
||||
return $this->comments;
|
||||
}
|
||||
|
||||
public function addComment(Comment $comment): self
|
||||
{
|
||||
if (!$this->comments->contains($comment)) {
|
||||
$this->comments[] = $comment;
|
||||
$comment->setAuthor($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
if (!$this->comments->contains($comment)) {
|
||||
$this->comments[] = $comment;
|
||||
$comment->setAuthor($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeComment(Comment $comment): self
|
||||
{
|
||||
if ($this->comments->removeElement($comment)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($comment->getAuthor() === $this) {
|
||||
$comment->setAuthor(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
{
|
||||
if ($this->comments->removeElement($comment)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($comment->getAuthor() === $this) {
|
||||
$comment->setAuthor(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isVerified(): bool
|
||||
{
|
||||
return $this->isVerified;
|
||||
}
|
||||
|
||||
public function setIsVerified(bool $isVerified): self
|
||||
{
|
||||
$this->isVerified = $isVerified;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
55
src/Form/RegistrationFormType.php
Normal file
55
src/Form/RegistrationFormType.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\IsTrue;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class RegistrationFormType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('username')
|
||||
->add('agreeTerms', CheckboxType::class, [
|
||||
'mapped' => false,
|
||||
'constraints' => [
|
||||
new IsTrue([
|
||||
'message' => 'You should agree to our terms.',
|
||||
]),
|
||||
],
|
||||
])
|
||||
->add('plainPassword', PasswordType::class, [
|
||||
// instead of being set onto the object directly,
|
||||
// this is read and encoded in the controller
|
||||
'mapped' => false,
|
||||
'attr' => ['autocomplete' => 'new-password'],
|
||||
'constraints' => [
|
||||
new NotBlank([
|
||||
'message' => 'Please enter a password',
|
||||
]),
|
||||
new Length([
|
||||
'min' => 6,
|
||||
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||
// max length allowed by Symfony for security reasons
|
||||
'max' => 4096,
|
||||
]),
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => User::class,
|
||||
]);
|
||||
}
|
||||
}
|
66
src/Security/EmailVerifier.php
Normal file
66
src/Security/EmailVerifier.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
|
||||
use SymfonyCasts\Bundle\VerifyEmail\VerifyEmailHelperInterface;
|
||||
|
||||
/**
|
||||
* Class EmailVerifier
|
||||
* @package App\Security
|
||||
*/
|
||||
class EmailVerifier
|
||||
{
|
||||
private VerifyEmailHelperInterface $verifyEmailHelper;
|
||||
private MailerInterface $mailer;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(VerifyEmailHelperInterface $helper, MailerInterface $mailer, EntityManagerInterface $manager)
|
||||
{
|
||||
$this->verifyEmailHelper = $helper;
|
||||
$this->mailer = $mailer;
|
||||
$this->entityManager = $manager;
|
||||
}
|
||||
|
||||
public function sendEmailConfirmation(string $verifyEmailRouteName, UserInterface $user, TemplatedEmail $email): void
|
||||
{
|
||||
$signatureComponents = $this->verifyEmailHelper->generateSignature(
|
||||
$verifyEmailRouteName,
|
||||
$user->getId(),
|
||||
$user->getEmail(),
|
||||
['id' => $user->getId()]
|
||||
);
|
||||
|
||||
$context = $email->getContext();
|
||||
$context['signedUrl'] = $signatureComponents->getSignedUrl();
|
||||
$context['expiresAtMessageKey'] = $signatureComponents->getExpirationMessageKey();
|
||||
$context['expiresAtMessageData'] = $signatureComponents->getExpirationMessageData();
|
||||
|
||||
$email->context($context);
|
||||
|
||||
try {
|
||||
$this->mailer->send($email);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
die("Error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws VerifyEmailExceptionInterface
|
||||
*/
|
||||
public function handleEmailConfirmation(Request $request, UserInterface $user): void
|
||||
{
|
||||
$this->verifyEmailHelper->validateEmailConfirmation($request->getUri(), $user->getId(), $user->getEmail());
|
||||
|
||||
$user->setIsVerified(true);
|
||||
|
||||
$this->entityManager->persist($user);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user