updrade with rector

This commit is contained in:
2022-05-03 14:52:04 +02:00
parent d1e613ecc6
commit 6e30560cb9
135 changed files with 5609 additions and 4008 deletions
.env.gitignore.php-cs-fixer.cache.php-cs-fixer.php
assets
composer.jsoncomposer.lock
config
migrations
package.json
public/uploads
rector.php
src
symfony.lock
templates
tools/php-cs-fixer
webpack.config.jsyarn.lock

@ -1,39 +0,0 @@
<?php
namespace App\Controller\Admin;
use App\Entity\Blog;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\SlugField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
/**
* Class BlogCrudController
* @package App\Controller\Admin
*/
class BlogCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Blog::class;
}
public function configureFields(string $pageName): iterable
{
return [
AssociationField::new('author')
->autocomplete(),
TextField::new('title'),
SlugField::new('slug')
->setTargetFieldName('title'),
TextEditorField::new('teaser'),
TextEditorField::new('content'),
DateTimeField::new('createdAt'),
AssociationField::new('editedBy')
->autocomplete()
];
}
}

@ -1,39 +0,0 @@
<?php
namespace App\Controller\Admin;
use App\Entity\Comment;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
/**
* Class CommentCrudController
* @package App\Controller\Admin
*/
class CommentCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Comment::class;
}
public function configureFields(string $pageName): iterable
{
return [
AssociationField::new('author')
->autocomplete(),
AssociationField::new('blog')
->autocomplete(),
TextField::new('title'),
TextEditorField::new('content'),
DateTimeField::new('createdAt'),
AssociationField::new('editedBy')
->autocomplete(),
DateTimeField::new('editedAt'),
];
}
}

@ -2,6 +2,7 @@
namespace App\Controller\Admin;
use App\Entity\Pages;
use App\Entity\Projects;
use App\Entity\Quotes;
use App\Entity\User;
@ -18,50 +19,45 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\UserInterface;
/**
*
*/
class DashboardController extends AbstractDashboardController
{
#[isGranted(data: 'ROLE_ADMIN')]
#[Route(path: '/admin', name: 'admin')]
public function index(): Response
{
//return parent::index();
return $this->render(view: 'admin/index.html.twig');
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle(title: '24unix Admin');
}
public function configureMenuItems(): iterable
{
yield MenuItem::linkToUrl(label: 'Homepage', icon: 'fa fa-home', url: $this->generateUrl(route: 'app_main'));
yield MenuItem::linkToDashboard(label: 'Dashboard', icon: 'fa fa-dashboard');
yield MenuItem::linkToCrud(label: 'Projects', icon: 'fa fa-file-code-o', entityFqcn: Projects::class);
yield MenuItem::linkToCrud(label: 'Users', icon: 'fa fa-users', entityFqcn: User::class);
yield MenuItem::linkToCrud(label: 'Quotes', icon: 'fa fa-quote-left', entityFqcn: Quotes::class);
}
public function configureUserMenu(UserInterface $user): UserMenu
{
if (!$user instanceof User) {
throw new Exception(message: 'Wrong User!');
}
return parent::configureUserMenu(user: $user)
->setAvatarUrl(url: $user->getAvatar());
}
public function configureActions(): Actions
{
return parent::configureActions()
->add(pageName: Crud::PAGE_INDEX, actionNameOrObject: Action::DETAIL);
}
#[isGranted(data: 'ROLE_ADMIN')]
#[Route(path: '/admin', name: 'admin')]
public function index(): Response
{
// return parent::index();
return $this->render(view: 'admin/index.html.twig');
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle(title: '24unix Admin');
}
public function configureMenuItems(): iterable
{
yield MenuItem::linkToUrl(label: 'Homepage', icon: 'fa fa-home', url: $this->generateUrl(route: 'app_main'));
yield MenuItem::linkToDashboard(label: 'Dashboard', icon: 'fa fa-dashboard');
yield MenuItem::linkToCrud(label: 'Users', icon: 'fa fa-users', entityFqcn: User::class);
yield MenuItem::linkToCrud(label: 'Projects', icon: 'fa fa-file-code-o', entityFqcn: Projects::class);
yield MenuItem::linkToCrud(label: 'Pages', icon: 'fa fa-newspaper-o', entityFqcn: Pages::class);
yield MenuItem::linkToCrud(label: 'Quotes', icon: 'fa fa-quote-left', entityFqcn: Quotes::class);
}
public function configureUserMenu(UserInterface $user): UserMenu
{
if (!$user instanceof User) {
throw new Exception(message: 'Wrong User!');
}
return parent::configureUserMenu(user: $user)
->setAvatarUrl(url: 'build/images/'.$user->getAvatar());
}
public function configureActions(): Actions
{
return parent::configureActions()
->add(pageName: Crud::PAGE_INDEX, actionNameOrObject: Action::DETAIL);
}
}

@ -0,0 +1,30 @@
<?php
namespace App\Controller\Admin;
use App\Entity\Pages;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\CodeEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
class PagesCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Pages::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'name');
yield AssociationField::new(propertyName: 'owner');
// yield CodeEditorField::new(propertyName: 'content')
yield TextareaField::new(propertyName: 'content')
->onlyOnForms();
}
}

@ -8,27 +8,23 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
/**
*
*/
class ProjectsCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Projects::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'name');
yield TextField::new(propertyName: 'description');
yield TextField::new(propertyName: 'description');
yield ImageField::new(propertyName: 'teaserImage')
->setBasePath(path: 'uploads/projects')
->setUploadDir(uploadDirPath: 'public/uploads/projects')
->setUploadedFileNamePattern(patternOrCallable: '[timestamp]-[slug].[extension]');
}
public static function getEntityFqcn(): string
{
return Projects::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'name');
yield TextField::new(propertyName: 'description');
yield TextField::new(propertyName: 'description');
yield ImageField::new(propertyName: 'teaserImage')
->setBasePath(path: 'uploads/projects')
->setUploadDir(uploadDirPath: 'public/uploads/projects')
->setUploadedFileNamePattern(patternOrCallable: '[timestamp]-[slug].[extension]');
}
}

@ -8,23 +8,20 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
/**
*
*/
class QuotesCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Quotes::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'quote')
->onlyOnIndex();
yield TextEditorField::new(propertyName: 'quote')
->onlyOnForms();
}
public static function getEntityFqcn(): string
{
return Quotes::class;
}
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'quote')
->onlyOnIndex();
yield TextEditorField::new(propertyName: 'quote')
->onlyOnForms();
}
}

@ -1,29 +0,0 @@
<?php
namespace App\Controller\Admin;
use App\Entity\Section;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
/**
* Class SectionCrudController
* @package App\Controller\Admin
*/
class SectionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Section::class;
}
/*
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id'),
TextField::new('title'),
TextEditorField::new('description'),
];
}
*/
}

@ -10,9 +10,6 @@ use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
/**
*
*/
class UserCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
@ -22,20 +19,20 @@ class UserCrudController extends AbstractCrudController
public function configureFields(string $pageName): iterable
{
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'firstName');
yield TextField::new(propertyName: 'lastName');
yield EmailField::new(propertyName: 'email');
yield ImageField::new(propertyName: 'avatar')
->setBasePath(path: 'uploads/avatars')
->setUploadDir(uploadDirPath: 'public/uploads/avatars')
->setUploadedFileNamePattern(patternOrCallable: '[timestamp]-[slug].[extension]');
$roles = ['ROLE_FOUNDER', 'ROLE_ADMIN', 'ROLE_MODERATOR', 'ROLE_USER'];
yield ChoiceField::new(propertyName: 'roles')
->setChoices(choiceGenerator: array_combine(keys: $roles, values: $roles))
->allowMultipleChoices()
->renderExpanded()
->renderAsBadges();
yield IdField::new(propertyName: 'id')
->onlyOnIndex();
yield TextField::new(propertyName: 'firstName');
yield TextField::new(propertyName: 'lastName');
yield EmailField::new(propertyName: 'email');
yield ImageField::new(propertyName: 'avatar')
->setBasePath(path: 'uploads/avatars')
->setUploadDir(uploadDirPath: 'public/uploads/avatars')
->setUploadedFileNamePattern(patternOrCallable: '[timestamp]-[slug].[extension]');
$roles = ['ROLE_FOUNDER', 'ROLE_ADMIN', 'ROLE_MODERATOR', 'ROLE_USER'];
yield ChoiceField::new(propertyName: 'roles')
->setChoices(choiceGenerator: array_combine(keys: $roles, values: $roles))
->allowMultipleChoices()
->renderExpanded()
->renderAsBadges();
}
}

@ -1,97 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\Blog;
use App\Form\BlogFormType;
use App\Repository\BlogRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class BlogController
* @package App\Controller
*/
class BlogController extends AbstractController
{
#[Route('/', name: 'blogs')]
public function index(BlogRepository $blogRepository): Response
{
return $this->render('blog/index.html.twig', [
'blogs' => $blogRepository->findAll()
]);
}
/**
* @param $slug
* @param \App\Repository\BlogRepository $blogRepository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog_show/{slug}', name: 'blog')]
public function show($slug, BlogRepository $blogRepository): Response
{
return $this->render('blog/show.html.twig', [
'blog' => $blogRepository->findOneBy(['slug' => $slug])
]);
}
/**
* @param \Doctrine\ORM\EntityManagerInterface $entityManager
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog/new', name: 'blog_new')]
public function new(EntityManagerInterface $entityManager, Request $request): RedirectResponse|Response
{
$form = $this->createForm(BlogFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$blog = $form->getData();
$entityManager->persist($blog);
$entityManager->flush();
return $this->redirectToRoute('blogs');
}
return $this->render('blog/new.html.twig', [
'blogForm' => $form->createView(),
]);
}
/**
* @param \App\Entity\Blog $blog
* @param \Symfony\Component\HttpFoundation\Request $request
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
#[Route('/blog/edit/{id}', name: 'blog_edit')]
public function edit(Blog $blog, Request $request): Response|RedirectResponse
{
$form = $this->createForm(BlogFormType::class, $blog);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$blog = $form->getData();
//$blog->setAuthor($this->getUser());
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($blog);
$entityManager->flush();
return $this->redirectToRoute('blogs');
}
return $this->render('blog/new.html.twig', [
'blogForm' => $form->createView(),
]);
}
}

@ -0,0 +1,33 @@
<?php
// src/Controller/FrontendController.php
namespace App\Controller;
use App\Repository\QuotesRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
/**
*
*/
class FrontendController extends AbstractController
{
/**
* @throws \Exception
*/
#[Route(path: '/', name: 'app_main')]
#[Route(path: '/{route}', name: 'vue_pages', requirements: ['route' => '^(?!.*_wdt|_profiler|login|logout).+'] )]
public function quote(SerializerInterface $serializer, QuotesRepository $quotesRepository): Response
{
$quote = $quotesRepository->findOneRandom();
return $this->render(view: 'base.html.twig', parameters: [
'user' => $serializer->serialize(data: $this->getUser(), format: 'jsonld'),
'quote' => json_encode(value: $quote->getQuote())
]);
}
}

@ -1,29 +0,0 @@
<?php
// src/Controller/LuckyController.php
namespace App\Controller;
use App\Repository\QuotesRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
*
*/
class MainController extends AbstractController
{
/**
* @throws \Exception
*/
#[Route(path: '/', name: 'app_main')]
public function quote(QuotesRepository $quotesRepository): Response
{
$quote = $quotesRepository->findOneRandom();
return $this->render(view: 'base.html.twig', parameters: [
'quote' => $quote->getQuote()
]);
}
}

@ -2,28 +2,29 @@
namespace App\Controller;
use App\Entity\Pages;
use App\Repository\PagesRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
*
*/
class PagesController extends AbstractController
{
#[Route(path: '/imprint', name: 'app_imprint')]
public function imprint(): Response
#[Route(path: '/pages/{name}', name: 'pages_display')]
public function display(PagesRepository $pagesRepository, string $name): Response
{
return $this->render(view: 'pages/imprint.html.twig', parameters: [
'controller_name' => 'PagesController',
$page = $pagesRepository->findOneBy([
'slug' => $name,
]);
if (!$page) {
$page = new Pages();
$page->setName(name: 'Not Found');
$page->setContent(content: 'The requested page was not found.');
}
return $this->render(view: 'pages/display.html.twig', parameters: [
'page' => $page,
]);
}
#[Route(path: '/privacy', name: 'app_privacy')]
public function privacy(): Response
{
return $this->render(view: 'pages/privacy.html.twig', parameters: [
'controller_name' => 'PagesController',
]);
}
}

@ -2,36 +2,33 @@
namespace App\Controller;
use App\Repository\ProjectsRepository;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Repository\ProjectsRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
*
*/
class ProjectsController extends AbstractController
{
#[Route(path: '/projects/{name}', name: 'app_projects')]
public function index(ProjectsRepository $projectsRepository, string $name = ''): Response
{
if ($name == '') {
return $this->render(view: 'projects/index.html.twig', parameters: [
'projects' => $projectsRepository->findAll()
]);
} else {
if ($project = $projectsRepository->findOneByName(value: $name)) {
$readMe = file_get_contents(filename: $project->getURL() . '/raw/branch/master/README.md');
//$parsedReadMe = $markdownParser->transformMarkdown(text: $readMe);
return $this->render(view: 'projects/show.html.twig', parameters: [
'project' => $project,
'readme' => $readMe
]);
} else {
throw $this->createNotFoundException();
}
}
}
#[Route(path: '/projects/{name}', name: 'app_projects')]
public function index(ProjectsRepository $projectsRepository, string $name = ''): Response
{
if ($name == '') {
return $this->render(view: 'projects/index.html.twig', parameters: [
'projects' => $projectsRepository->findAll(),
]);
} else {
if ($project = $projectsRepository->findOneByName(value: $name)) {
$readMe = file_get_contents(filename: $project->getURL().'/raw/branch/master/README.md');
// $parsedReadMe = $markdownParser->transformMarkdown(text: $readMe);
return $this->render(view: 'projects/show.html.twig', parameters: [
'project' => $project,
'readme' => $readMe,
]);
} else {
throw $this->createNotFoundException();
}
}
}
}

@ -1,98 +0,0 @@
<?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\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
/**
* Class RegistrationController
* @package App\Controller
*/
class RegistrationController extends AbstractController
{
private $emailVerifier;
public function __construct(EmailVerifier $emailVerifier)
{
$this->emailVerifier = $emailVerifier;
}
#[Route('/register', name: 'app_register')]
public function register(Request $request, UserPasswordHasherInterface $passwordHasher): Response
{
$user = new User();
$form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// hash the plain password
$user->setPassword(
$passwordHasher->hashPassword(
$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('security/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 ($id === null) {
return $this->redirectToRoute('app_login');
}
$user = $userRepository->find($id);
if ($user === null) {
return $this->redirectToRoute('app_login');
}
// 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_login');
}
// @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('blogs');
}
}

@ -1,179 +0,0 @@
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\ChangePasswordFormType;
use App\Form\ResetPasswordRequestFormType;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use SymfonyCasts\Bundle\ResetPassword\Controller\ResetPasswordControllerTrait;
use SymfonyCasts\Bundle\ResetPassword\Exception\ResetPasswordExceptionInterface;
use SymfonyCasts\Bundle\ResetPassword\ResetPasswordHelperInterface;
/**
* Class ResetPasswordController
* @package App\Controller
*/
#[Route('/reset-password')]
class ResetPasswordController extends AbstractController
{
use ResetPasswordControllerTrait;
private $resetPasswordHelper;
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper)
{
$this->resetPasswordHelper = $resetPasswordHelper;
}
/**
* Display & process form to request a password reset.
*/
#[Route('', name: 'app_forgot_password_request')]
public function request(Request $request, MailerInterface $mailer): Response
{
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->processSendingPasswordResetEmail(
$form->get('email')->getData(),
$mailer
);
}
return $this->render('security/request.html.twig', [
'requestForm' => $form->createView(),
]);
}
/**
* Confirmation page after a user has requested a password reset.
*/
#[Route('/check-email', name: 'app_check_email')]
public function checkEmail(): Response
{
// Generate a fake token if the user does not exist or someone hit this page directly.
// This prevents exposing whether or not a user was found with the given email address or not
if (null === ($resetToken = $this->getTokenObjectFromSession())) {
$resetToken = $this->resetPasswordHelper->generateFakeResetToken();
}
return $this->render('security/check_email.html.twig', [
'resetToken' => $resetToken,
]);
}
/**
* Validates and process the reset URL that the user clicked in their email.
*/
#[Route('/reset/{token}', name: 'app_reset_password')]
public function reset(Request $request, UserPasswordHasherInterface $passwordHasher, string $token = null): Response
{
if ($token) {
// We store the token in session and remove it from the URL, to avoid the URL being
// loaded in a browser and potentially leaking the token to 3rd party JavaScript.
$this->storeTokenInSession($token);
return $this->redirectToRoute('app_reset_password');
}
$token = $this->getTokenFromSession();
if ($token === null) {
throw $this->createNotFoundException('No reset password token found in the URL or in the session.');
}
try {
$user = $this->resetPasswordHelper->validateTokenAndFetchUser($token);
} catch (ResetPasswordExceptionInterface $e) {
$this->addFlash('reset_password_error', sprintf(
'There was a problem validating your reset request - %s',
$e->getReason()
));
return $this->redirectToRoute('app_forgot_password_request');
}
// The token is valid; allow the user to change their password.
$form = $this->createForm(ChangePasswordFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// A password reset token should be used only once, remove it.
$this->resetPasswordHelper->removeResetRequest($token);
// Hash the plain password, and set it.
/*
** @var PasswordAuthenticatedUserInterface $user
*/
$hashedPassword = $passwordHasher->hashPassword(
$user,
$form->get('plainPassword')->getData()
);
$user->setPassword($hashedPassword);
$this->getDoctrine()->getManager()->flush();
// The session is cleaned up after the password has been changed.
$this->cleanSessionAfterReset();
return $this->redirectToRoute('blogs');
}
return $this->render('security/reset.html.twig', [
'resetForm' => $form->createView(),
]);
}
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer): RedirectResponse
{
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy([
'email' => $emailFormData,
]);
// Do not reveal whether a user account was found or not.
if (!$user) {
return $this->redirectToRoute('app_check_email');
}
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (ResetPasswordExceptionInterface $e) {
// If you want to tell the user why a reset email was not sent, uncomment
// the lines below and change the redirect to 'app_forgot_password_request'.
// Caution: This may reveal if a user is registered or not.
//
// $this->addFlash('reset_password_error', sprintf(
// 'There was a problem handling your password reset request - %s',
// $e->getReason()
// ));
return $this->redirectToRoute('app_check_email');
}
$email = (new TemplatedEmail())
->from(new Address('tracer@24unix.net', '24unix.net'))
->to($user->getEmail())
->subject('Your password reset request')
->htmlTemplate('security/email.html.twig')
->context([
'resetToken' => $resetToken,
]);
$mailer->send($email);
// Store the token object in session for retrieval in check-email route.
$this->setTokenObjectInSession($resetToken);
return $this->redirectToRoute('app_check_email');
}
}

@ -2,21 +2,44 @@
namespace App\Controller;
use ApiPlatform\Core\Api\IriConverterInterface;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
/**
*
*/
class SecurityController extends AbstractController
{
#[Route(path: '/login', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
#[Route(path: '/login', name: 'app_login')] // *** method post
public function login(AuthenticationUtils $authenticationUtils, IriConverterInterface $iriConverter): Response
{
if (!$this->isGranted(attribute: 'IS_AUTHENTICATED_FULLY')) {
return $this->json(data: [
'error' => 'Invalid login request'
], status: 400);
}
/** @var User $user */
$user = $this->getUser() ?? null;
return new Response(content: null, status: 204, headers: [
'Location' => $iriConverter->getIriFromItem(item: $user)
]);
}
/*
return $this->render(view: 'security/login.html.twig', parameters: [
'error' => $authenticationUtils->getLastAuthenticationError(),
'last_username' => $authenticationUtils->getLastUsername(),
]);
*
}
/**

@ -11,65 +11,78 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
/**
* Class UserController
* @package App\Controller
* Class UserController.
*/
class UserController extends AbstractController
{
/**
* @param \App\Repository\UserRepository $userRepository
* @param string $userName
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route(path: '/profile/edit/{username}', name: 'app_profile_edit')]
public function editProfile(UserRepository $userRepository, string $username = ''): Response
{
/** var User $user */
if ($username === '') {
if ($this->isGranted(attribute: 'ROLE_USER')) {
$user = $this->getUser();
} else {
throw new AccessDeniedException(message: 'You need to be logged in.');
}
} else {
if ($this->isGranted(attribute: 'ROLE_ADMIN')) {
$user = $userRepository->findOneBy([
"username" => $username
]);
}
}
if (isset($user)) {
return $this->render(view: 'user/edit_profile.html.twig', parameters: [
'user' => $user,
]);
} else {
throw new UserNotFoundException();
}
}
/**
* @param \App\Repository\UserRepository $userRepository
* @param string $username
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route(path: '/profile/{username}', name: 'app_profile')]
public function showProfile(UserRepository $userRepository, string $username = ''): Response
{
/** var User $user */
if ($username === '') {
$user = $this->getUser();
} else {
$user = $userRepository->findOneBy([
"username" => $username
]);
}
return $this->render(view: 'user/show_profile.html.twig', parameters: [
'user' => $user,
]);
}
/**
* @param \App\Repository\UserRepository $userRepository
* @param string $userName
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route(path: '/profile/edit/{username}', name: 'app_profile_edit')]
public function editProfile(UserRepository $userRepository, string $username = ''): Response
{
/* var User $user */
if ($username === '') {
if ($this->isGranted(attribute: 'ROLE_USER')) {
$user = $this->getUser();
} else {
throw new AccessDeniedException(message: 'You need to be logged in.');
}
} else {
if ($this->isGranted(attribute: 'ROLE_ADMIN')) {
$user = $userRepository->findOneBy([
'username' => $username,
]);
}
}
if (isset($user)) {
return $this->render(view: 'user/edit_profile.html.twig', parameters: [
'user' => $user,
]);
} else {
throw new UserNotFoundException();
}
}
/**
* @param \App\Repository\UserRepository $userRepository
* @param string $username
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route(path: '/profile/{username}', name: 'app_profile')]
public function showProfile(UserRepository $userRepository, string $username = ''): Response
{
/* var User $user */
if ($username === '') {
$user = $this->getUser();
} else {
$user = $userRepository->findOneBy([
'username' => $username,
]);
}
return $this->render(view: 'user/show_profile.html.twig', parameters: [
'user' => $user,
]);
}
/**
* @param \App\Repository\UserRepository $userRepository
*
* @return \Symfony\Component\HttpFoundation\Response
*/
#[Route(path: '/list_users/', name: 'app_list_user')]
public function listUsers(UserRepository $userRepository): Response
{
$users = $userRepository->findAll();
return $this->render(view: 'user/list_users.html.twig', parameters: [
'users' => $users,
]);
}
}

@ -1,299 +0,0 @@
<?php
namespace App\Entity;
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 Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\String\Slugger\SluggerInterface;
/**
* @ORM\Entity(repositoryClass=BlogRepository::class)
* @ORM\HasLifecycleCallbacks()
* @UniqueEntity("slug")
*/
class Blog
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private ?string $title;
/**
* @ORM\Column(type="text", nullable=true)
*/
private ?string $teaser;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private ?string $teaserImage;
/**
* @ORM\Column(type="text")
*/
private ?string $content;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="blogs")
* @ORM\JoinColumn(nullable=false)
*/
private ?User $author;
/**
* @ORM\ManyToMany(targetEntity=Section::class, inversedBy="blogs")
*/
private $section;
/**
* @ORM\Column(type="datetime")
*/
private ?\DateTimeInterface $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private ?\DateTimeInterface $editedAt;
/**
* @ORM\ManyToOne(targetEntity=User::class)
*/
private ?User $editedBy;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private ?string $editReason;
/**
* @ORM\OneToMany(targetEntity=Comment::class, mappedBy="blog")
*/
private $comments;
/**
* @ORM\Column(type="string", length=255, unique=true)
*/
private $slug;
#[Pure]
public function __construct()
{
$this->section = new ArrayCollection();
$this->comments = new ArrayCollection();
}
/**
* @return null|string
*/
public function __toString()
{
return $this->title;
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getTeaser(): ?string
{
return $this->teaser;
}
public function setTeaser(?string $teaser): self
{
$this->teaser = $teaser;
return $this;
}
public function getTeaserImage(): ?string
{
return $this->teaserImage;
}
public function setTeaserImage(?string $teaserImage): self
{
$this->teaserImage = $teaserImage;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
/**
* @return Collection|Section[]
*/
public function getSection(): Collection
{
return $this->section;
}
public function addSection(Section $section): self
{
if (!$this->section->contains($section)) {
$this->section[] = $section;
}
return $this;
}
public function removeSection(Section $section): self
{
$this->section->removeElement($section);
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getEditedAt(): ?\DateTimeInterface
{
return $this->editedAt;
}
public function setEditedAt(?\DateTimeInterface $editedAt): self
{
$this->editedAt = $editedAt;
return $this;
}
public function getEditedBy(): ?User
{
return $this->editedBy;
}
public function setEditedBy(?User $editedBy): self
{
$this->editedBy = $editedBy;
return $this;
}
public function getEditReason(): ?string
{
return $this->editReason;
}
public function setEditReason(?string $editReason): self
{
$this->editReason = $editReason;
return $this;
}
/**
* @return Collection|Comment[]
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comment $comment): self
{
if (!$this->comments->contains($comment)) {
$this->comments[] = $comment;
$comment->setBlog($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->getBlog() === $this) {
$comment->setBlog(null);
}
}
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* @ORM\PrePersist
*/
public function onPrePersist()
{
$this->createdAt = new \DateTime();
}
/**
* @param SluggerInterface $slugger
*/
public function computeSlug(SluggerInterface $slugger)
{
$this->slug = $slugger->slug($this->title);
}
}

@ -1,162 +0,0 @@
<?php
namespace App\Entity;
use App\Repository\CommentRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=CommentRepository::class)
*/
class Comment
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Blog::class, inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $blog;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $title;
/**
* @ORM\Column(type="text")
*/
private $content;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $author;
/**
* @ORM\Column(type="datetime")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $editedAt;
/**
* @ORM\ManyToOne(targetEntity=User::class)
*/
private $editedBy;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $editReason;
public function getId(): ?int
{
return $this->id;
}
public function getBlog(): ?Blog
{
return $this->blog;
}
public function setBlog(?Blog $blog): self
{
$this->blog = $blog;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(?string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getEditedAt(): ?\DateTimeInterface
{
return $this->editedAt;
}
public function setEditedAt(?\DateTimeInterface $editedAt): self
{
$this->editedAt = $editedAt;
return $this;
}
public function getEditedBy(): ?User
{
return $this->editedBy;
}
public function setEditedBy(?User $editedBy): self
{
$this->editedBy = $editedBy;
return $this;
}
public function getEditReason(): ?string
{
return $this->editReason;
}
public function setEditReason(?string $editReason): self
{
$this->editReason = $editReason;
return $this;
}
}

152
src/Entity/Pages.php Normal file

@ -0,0 +1,152 @@
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Repository\PagesRepository;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Sunrise\Slugger\Slugger;
#[ORM\Entity(repositoryClass: PagesRepository::class), ORM\HasLifecycleCallbacks]
#[ApiResource]
#[ApiFilter(filterClass: SearchFilter::class, properties: ['slug' => 'exact'])]
class Pages
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private $id;
#[ORM\Column(type: 'string', length: 255)]
private $name;
#[ORM\Column(type: 'text')]
private $content;
#[ORM\Column(type: 'datetime_immutable')]
private $createdAt;
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
private $modifiedAt;
#[ORM\ManyToOne(targetEntity: User::class, inversedBy: 'pages')]
#[ORM\JoinColumn(nullable: false)]
private $owner;
#[ORM\Column(type: 'string', length: 255)]
private $slug;
/**
* @param $id
*/
/* public function __construct(String $name = '', String $content = '')
{
$this->name = $name;
$this->content = $content;
$owner = $userRepository->findOneBy(['username' => 'tracer']);
$this->owner = $owner;
}
*/
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getCreatedAt(): ?DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(DateTimeImmutable $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getModifiedAt(): ?DateTimeImmutable
{
return $this->modifiedAt;
}
public function setModifiedAt(?DateTimeImmutable $modifiedAt): self
{
$this->modifiedAt = $modifiedAt;
return $this;
}
public function getOwner(): ?User
{
return $this->owner;
}
public function setOwner(?User $owner): self
{
$this->owner = $owner;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
#[ORM\PrePersist]
public function onPrePersist(): void
{
$slugger = new Slugger();
$slug = $slugger->slugify(string: $this->name);
$this->slug = $slug;
$this->createdAt = new DateTimeImmutable(datetime: 'now');
}
#[ORM\PreUpdate]
public function onPreUpdate(): void
{
$slugger = new Slugger();
$slug = $slugger->slugify(string: $this->name);
$this->slug = $slug;
$this->modifiedAt = new DateTimeImmutable(datetime: 'now');
}
}

@ -2,15 +2,14 @@
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\ProjectsRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
*
*/
#[ORM\Entity(repositoryClass: ProjectsRepository::class)]
#[ApiResource]
class Projects
{
#[ORM\Id]
@ -40,16 +39,16 @@ class Projects
{
$this->developer = new ArrayCollection();
}
/**
* @return null|string
*/
public function __toString()
{
return $this->name;
}
public function getId(): ?int
/**
* @return string|null
*/
public function __toString()
{
return $this->name;
}
public function getId(): ?int
{
return $this->id;
}

@ -2,10 +2,12 @@
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\QuotesRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: QuotesRepository::class)]
#[ApiResource]
class Quotes
{
#[ORM\Id]

@ -1,45 +0,0 @@
<?php
namespace App\Entity;
use App\Repository\ResetPasswordRequestRepository;
use Doctrine\ORM\Mapping as ORM;
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestInterface;
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestTrait;
/**
* @ORM\Entity(repositoryClass=ResetPasswordRequestRepository::class)
*/
class ResetPasswordRequest implements ResetPasswordRequestInterface
{
use ResetPasswordRequestTrait;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=User::class)
* @ORM\JoinColumn(nullable=false)
*/
private $user;
public function __construct(object $user, \DateTimeInterface $expiresAt, string $selector, string $hashedToken)
{
$this->user = $user;
$this->initialize($expiresAt, $selector, $hashedToken);
}
public function getId(): ?int
{
return $this->id;
}
public function getUser(): object
{
return $this->user;
}
}

@ -1,114 +0,0 @@
<?php
namespace App\Entity;
use App\Repository\SectionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=SectionRepository::class)
*/
class Section
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $title;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $description;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $teaserImage;
/**
* @ORM\ManyToMany(targetEntity=Blog::class, mappedBy="section")
*/
private $blogs;
public function __construct()
{
$this->blogs = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getTeaserImage(): ?string
{
return $this->teaserImage;
}
public function setTeaserImage(?string $teaserImage): self
{
$this->teaserImage = $teaserImage;
return $this;
}
/**
* @return Collection|Blog[]
*/
public function getBlogs(): Collection
{
return $this->blogs;
}
public function addBlog(Blog $blog): self
{
if (!$this->blogs->contains($blog)) {
$this->blogs[] = $blog;
$blog->addSection($this);
}
return $this;
}
public function removeBlog(Blog $blog): self
{
if ($this->blogs->removeElement($blog)) {
$blog->removeSection($this);
}
return $this;
}
}

@ -2,224 +2,304 @@
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use App\Repository\UserRepository;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use PhpParser\Node\Scalar\String_;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
*
* => ["security" => "is_granted('ROLE_ADMIN') or object.owner == user"]
*/
#[ORM\Entity(repositoryClass: UserRepository::class)]
#[ORM\Table(name: '`user`')]
#[ORM\Entity(repositoryClass: UserRepository::class), ORM\HasLifecycleCallbacks]
#[ApiResource(
collectionOperations: ['get', 'post'],
itemOperations : ['get'],
attributes : ['security' => 'is_granted("ROLE_USER")']
)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
private string $username;
#[ORM\Column(type: 'json')]
private array $roles = [];
#[ORM\Column(type: 'string')]
private string $password;
private string $plainPassword;
#[ORM\Column(type: 'string', length: 255)]
private string $email;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $firstName = '';
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $lastName = '';
#[ORM\ManyToMany(targetEntity: Projects::class, mappedBy: 'developer')]
private $projects;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $avatar;
public function __construct()
{
$this->projects = new ArrayCollection();
}
/**
* @return null|string
*/
public function __toString()
{
return $this->username;
}
public function getId(): ?int
{
return $this->id;
}
/**
* @return string
*/
public function getPlainPassword(): string
{
return $this->plainPassword;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return $this->username;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique(array: $roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
$this->plainPassword = '';
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
/**
* @param string $plainPassword
*/
public function setPlainPassword(string $plainPassword): void
{
$this->plainPassword = $plainPassword;
}
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(?string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(?string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
/**
* @return Collection<int, Projects>
*/
public function getProjects(): Collection
{
return $this->projects;
}
public function addProject(Projects $project): self
{
if (!$this->projects->contains(element: $project)) {
$this->projects[] = $project;
$project->addDeveloper(developer: $this);
}
return $this;
}
public function removeProject(Projects $project): self
{
if ($this->projects->removeElement(element: $project)) {
$project->removeDeveloper(developer: $this);
}
return $this;
}
public function getAvatar(): string
{
return $this->avatar ?? '';
}
public function setAvatar(?string $avatar): self
{
$this->avatar = $avatar;
return $this;
}
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
private int $id;
#[ORM\Column(type: 'string', length: 180, unique: true)]
private string $username;
#[ORM\Column(type: 'json')]
private array $roles = [];
#[ORM\Column(type: 'string')]
private string $password;
private string $plainPassword;
#[ORM\Column(type: 'string', length: 255)]
private string $email;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $firstName = '';
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private ?string $lastName = '';
#[ORM\ManyToMany(targetEntity: Projects::class, mappedBy: 'developer')]
private $projects;
#[ORM\Column(type: 'string', length: 255, nullable: true)]
private $avatar;
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: Pages::class)]
private $pages;
#[ORM\Column(type: 'datetime_immutable')]
private $createdAt;
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
private $modifiedAt;
public function __construct()
{
$this->projects = new ArrayCollection();
$this->pages = new ArrayCollection();
}
/**
* @return string|null
*/
public function __toString()
{
return $this->username;
}
public function getId(): ?int
{
return $this->id;
}
public function getPlainPassword(): string
{
return $this->plainPassword;
}
public function getUsername(): ?string
{
return $this->username;
}
public function setUsername(string $username): self
{
$this->username = $username;
return $this;
}
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string
{
return $this->username;
}
/**
* @see UserInterface
*/
public function getRoles(): array
{
$roles = $this->roles;
// guarantee every user at least has ROLE_USER
$roles[] = 'ROLE_USER';
return array_unique(array: $roles);
}
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* @see UserInterface
*/
public function eraseCredentials()
{
$this->plainPassword = '';
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function setPlainPassword(string $plainPassword): void
{
$this->plainPassword = $plainPassword;
}
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(?string $firstName): self
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(?string $lastName): self
{
$this->lastName = $lastName;
return $this;
}
/**
* @return Collection<int, Projects>
*/
public function getProjects(): Collection
{
return $this->projects;
}
public function addProject(Projects $project): self
{
if (!$this->projects->contains(element: $project)) {
$this->projects[] = $project;
$project->addDeveloper(developer: $this);
}
return $this;
}
public function removeProject(Projects $project): self
{
if ($this->projects->removeElement(element: $project)) {
$project->removeDeveloper(developer: $this);
}
return $this;
}
public function getAvatar(): string
{
return $this->avatar ?? '';
}
public function setAvatar(?string $avatar): self
{
$this->avatar = $avatar;
return $this;
}
/**
* @return Collection<int, Pages>
*/
public function getPages(): Collection
{
return $this->pages;
}
public function addPage(Pages $page): self
{
if (!$this->pages->contains($page)) {
$this->pages[] = $page;
$page->setOwner($this);
}
return $this;
}
public function removePage(Pages $page): self
{
if ($this->pages->removeElement($page)) {
// set the owning side to null (unless already changed)
if ($page->getOwner() === $this) {
$page->setOwner(null);
}
}
return $this;
}
public function getCreatedAt(): ?DateTimeImmutable
{
return $this->createdAt;
}
public function setCreatedAt(DateTimeImmutable $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getModifiedAt(): ?DateTimeImmutable
{
return $this->modifiedAt;
}
public function setModifiedAt(?DateTimeImmutable $modifiedAt): self
{
$this->modifiedAt = $modifiedAt;
return $this;
}
public function getAvatarUri()
{
return 'avatar';
}
#[ORM\PrePersist]
public function onPrePersist(): void
{
$this->createdAt = new DateTimeImmutable(datetime: 'now');
}
#[ORM\PreUpdate]
public function onPreUpdate(): void
{
$this->modifiedAt = new DateTimeImmutable(datetime: 'now');
}
}

@ -1,43 +0,0 @@
<?php
namespace App\EntityListener;
use App\Entity\Blog;
use Doctrine\ORM\Event\LifecycleEventArgs;
use JetBrains\PhpStorm\NoReturn;
use Symfony\Component\String\Slugger\SluggerInterface;
/**
* Class BlogEntityListener
* @package App\EntityListener
*/
class BlogEntityListener
{
private SluggerInterface $slugger;
public function __construct(SluggerInterface $slugger)
{
$this->slugger = $slugger;
}
/**
* @param \App\Entity\Blog $blog
* @param \Doctrine\ORM\Event\LifecycleEventArgs $title
*/
#[NoReturn]
public function prePersist(Blog $blog, LifecycleEventArgs $title)
{
$blog->computeSlug($this->slugger);
}
/**
* @param \App\Entity\Blog $blog
* @param \Doctrine\ORM\Event\LifecycleEventArgs $title
*/
#[NoReturn]
public function preUpdate(Blog $blog, LifecycleEventArgs $title)
{
//dd($title);
$blog->computeSlug($this->slugger);
}
}

@ -1,40 +0,0 @@
<?php
namespace App\Form;
use App\Entity\Blog;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class BlogFormType
* @package App\Form
*/
class BlogFormType extends \Symfony\Component\Form\AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('teaser')
->add('content')
->add('author');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Blog::class
]);
}
}

@ -1,55 +0,0 @@
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* Class ChangePasswordFormType
* @package App\Form
*/
class ChangePasswordFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'first_options' => [
'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,
]),
],
'label' => 'New password',
],
'second_options' => [
'attr' => ['autocomplete' => 'new-password'],
'label' => 'Repeat Password',
],
'invalid_message' => 'The password fields must match.',
// Instead of being set onto the object directly,
// this is read and hashed in the controller
'mapped' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([]);
}
}

@ -1,68 +0,0 @@
<?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\EmailType;
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
* @package App\Form
*/
class RegistrationFormType extends AbstractType
{
/**
* {@inheritdoc}
*/
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 hashed 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,
]),
],
])
->add('firstName')
->add('lastName')
->add('email', EmailType::class);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}

@ -1,31 +0,0 @@
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class ResetPasswordRequestFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('email', EmailType::class, [
'attr' => ['autocomplete' => 'email'],
'constraints' => [
new NotBlank([
'message' => 'Please enter your email',
]),
],
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([]);
}
}

@ -1,50 +0,0 @@
<?php
namespace App\Repository;
use App\Entity\Blog;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Blog|null find($id, $lockMode = null, $lockVersion = null)
* @method Blog|null findOneBy(array $criteria, array $orderBy = null)
* @method Blog[] findAll()
* @method Blog[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class BlogRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Blog::class);
}
// /**
// * @return Blog[] Returns an array of Blog objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('b')
->andWhere('b.exampleField = :val')
->setParameter('val', $value)
->orderBy('b.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Blog
{
return $this->createQueryBuilder('b')
->andWhere('b.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

@ -1,50 +0,0 @@
<?php
namespace App\Repository;
use App\Entity\Comment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Comment|null find($id, $lockMode = null, $lockVersion = null)
* @method Comment|null findOneBy(array $criteria, array $orderBy = null)
* @method Comment[] findAll()
* @method Comment[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CommentRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Comment::class);
}
// /**
// * @return Comment[] Returns an array of Comment objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->orderBy('c.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Comment
{
return $this->createQueryBuilder('c')
->andWhere('c.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

@ -0,0 +1,68 @@
<?php
namespace App\Repository;
use App\Entity\Pages;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Pages>
*
* @method Pages|null find($id, $lockMode = null, $lockVersion = null)
* @method Pages|null findOneBy(array $criteria, array $orderBy = null)
* @method Pages[] findAll()
* @method Pages[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class PagesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct(registry: $registry, entityClass: Pages::class);
}
public function add(Pages $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
public function remove(Pages $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
// /**
// * @return Pages[] Returns an array of Pages objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->orderBy('p.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Pages
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

@ -20,8 +20,6 @@ class ProjectsRepository extends ServiceEntityRepository
parent::__construct(registry: $registry, entityClass: Projects::class);
}
/**
*/
public function add(Projects $entity, bool $flush = true): void
{
$this->_em->persist($entity);
@ -30,8 +28,6 @@ class ProjectsRepository extends ServiceEntityRepository
}
}
/**
*/
public function remove(Projects $entity, bool $flush = true): void
{
$this->_em->remove($entity);
@ -56,18 +52,20 @@ class ProjectsRepository extends ServiceEntityRepository
;
}
*/
public function findOneByName($value): ?Projects
/**
* @param $value
*/
public function findOneByName($value): ?Projects
{
try {
return $this->createQueryBuilder(alias: 'q')
->andWhere('q.name = :val')
->setParameter(key: 'val', value: $value)
->getQuery()
->getOneOrNullResult();
} catch(NonUniqueResultException $e) {
dd($e->getMessage());
}
try {
return $this->createQueryBuilder(alias: 'q')
->andWhere('q.name = :val')
->setParameter(key: 'val', value: $value)
->getQuery()
->getOneOrNullResult();
} catch (NonUniqueResultException $e) {
dd($e->getMessage());
}
}
}

@ -4,8 +4,6 @@ namespace App\Repository;
use App\Entity\Quotes;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\ManagerRegistry;
/**
@ -21,8 +19,6 @@ class QuotesRepository extends ServiceEntityRepository
parent::__construct(registry: $registry, entityClass: Quotes::class);
}
/**
*/
public function add(Quotes $entity, bool $flush = true): void
{
$this->_em->persist($entity);
@ -31,8 +27,6 @@ class QuotesRepository extends ServiceEntityRepository
}
}
/**
*/
public function remove(Quotes $entity, bool $flush = true): void
{
$this->_em->remove($entity);
@ -40,29 +34,28 @@ class QuotesRepository extends ServiceEntityRepository
$this->_em->flush();
}
}
/**
* @return null|float|int|mixed|string
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function findOneRandom(): mixed
{
$idLimits = $this->createQueryBuilder(alias: 'q')
->select('MIN(q.id)', 'MAX(q.id)')
->getQuery()
->getOneOrNullResult();
$randomPossibleId = rand(min: $idLimits[1], max: $idLimits[2]);
return $this->createQueryBuilder(alias: 'q')
->where(predicates: 'q.id >= :random_id')
->setParameter(key: 'random_id', value: $randomPossibleId)
->setMaxResults(maxResults: 1)
->getQuery()
->getOneOrNullResult();
}
/**
* @return float|int|mixed|string|null
*
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function findOneRandom(): mixed
{
$idLimits = $this->createQueryBuilder(alias: 'q')
->select('MIN(q.id)', 'MAX(q.id)')
->getQuery()
->getOneOrNullResult();
$randomPossibleId = rand(min: $idLimits[1], max: $idLimits[2]);
return $this->createQueryBuilder(alias: 'q')
->where(predicates: 'q.id >= :random_id')
->setParameter(key: 'random_id', value: $randomPossibleId)
->setMaxResults(maxResults: 1)
->getQuery()
->getOneOrNullResult();
}
// /**
// * @return Quotes[] Returns an array of Quotes objects
// */

@ -1,31 +0,0 @@
<?php
namespace App\Repository;
use App\Entity\ResetPasswordRequest;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use SymfonyCasts\Bundle\ResetPassword\Model\ResetPasswordRequestInterface;
use SymfonyCasts\Bundle\ResetPassword\Persistence\Repository\ResetPasswordRequestRepositoryTrait;
use SymfonyCasts\Bundle\ResetPassword\Persistence\ResetPasswordRequestRepositoryInterface;
/**
* @method ResetPasswordRequest|null find($id, $lockMode = null, $lockVersion = null)
* @method ResetPasswordRequest|null findOneBy(array $criteria, array $orderBy = null)
* @method ResetPasswordRequest[] findAll()
* @method ResetPasswordRequest[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ResetPasswordRequestRepository extends ServiceEntityRepository implements ResetPasswordRequestRepositoryInterface
{
use ResetPasswordRequestRepositoryTrait;
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ResetPasswordRequest::class);
}
public function createResetPasswordRequest(object $user, \DateTimeInterface $expiresAt, string $selector, string $hashedToken): ResetPasswordRequestInterface
{
return new ResetPasswordRequest($user, $expiresAt, $selector, $hashedToken);
}
}

@ -1,50 +0,0 @@
<?php
namespace App\Repository;
use App\Entity\Section;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Section|null find($id, $lockMode = null, $lockVersion = null)
* @method Section|null findOneBy(array $criteria, array $orderBy = null)
* @method Section[] findAll()
* @method Section[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class SectionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Section::class);
}
// /**
// * @return Section[] Returns an array of Section objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('s')
->andWhere('s.exampleField = :val')
->setParameter('val', $value)
->orderBy('s.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Section
{
return $this->createQueryBuilder('s')
->andWhere('s.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}

@ -5,10 +5,10 @@ namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use function get_class;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
use function get_class;
/**
* @method User|null find($id, $lockMode = null, $lockVersion = null)
@ -23,8 +23,6 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
parent::__construct(registry: $registry, entityClass: User::class);
}
/**
*/
public function add(User $entity, bool $flush = true): void
{
$this->_em->persist(entity: $entity);
@ -33,8 +31,6 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
}
}
/**
*/
public function remove(User $entity, bool $flush = true): void
{
$this->_em->remove(entity: $entity);

@ -1,191 +0,0 @@
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use JetBrains\PhpStorm\ArrayShape;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
/**
* Class AppAuthenticator
* @package App\Security
*/
class AppAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private EntityManagerInterface $entityManager;
private UrlGeneratorInterface $urlGenerator;
private CsrfTokenManagerInterface $csrfTokenManager;
private UserPasswordHasherInterface $passwordHasher;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordHasherInterface $passwordHasher)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordHasher = $passwordHasher;
}
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* @return bool
*/
public function supports(Request $request): bool
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
/**
* Get the authentication credentials from the request and return them
* as any type (e.g. an associate array).
*
* Whatever value you return here will be passed to getUser() and checkCredentials()
*
* For example, for a form login, you might:
*
* return [
* 'username' => $request->request->get('_username'),
* 'password' => $request->request->get('_password'),
* ];
*
* Or for an API token that's on a header, you might use:
*
* return ['api_key' => $request->headers->get('X-API-TOKEN')];
*
* @return array Any non-null value
*
* @throws \UnexpectedValueException If null is returned
*/
#[ArrayShape([
'username' => "mixed",
'password' => "mixed",
'csrf_token' => "mixed"
])]
public function getCredentials(Request $request): array
{
$credentials = [
'username' => $request->request->get('username'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['username']
);
return $credentials;
}
/**
* Return a UserInterface object based on the credentials.
*
* The *credentials* are the return value from getCredentials()
*
* You may throw an AuthenticationException if you wish. If you return
* null, then a UsernameNotFoundException is thrown for you.
*
* @param mixed $credentials
*
* @return UserInterface|null
* @throws AuthenticationException
*
*/
public function getUser($credentials, UserProviderInterface $userProvider): ?UserInterface
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
// try username
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $credentials['username']]);
// try email
if (!$user) {
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['username']]);
}
if (!$user) {
throw new UserNotFoundException('Username or email could not be found.');
} else {
return $user;
}
}
/**
* Returns true if the credentials are valid.
*
* If false is returned, authentication will fail. You may also throw
* an AuthenticationException if you wish to cause authentication to fail.
*
* The *credentials* are the return value from getCredentials()
*
* @param mixed $credentials
*
* @return bool
*
* @throws AuthenticationException
*/
public function checkCredentials($credentials, UserInterface $user): bool
{
//return true;
return $this->passwordHasher->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
/**
* Called when authentication executed and was successful!
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the last page they visited.
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('blogs'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}

@ -1,66 +0,0 @@
<?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();
}
}

@ -3,6 +3,7 @@
namespace App\Security;
use App\Entity\User;
use App\Repository\UserRepository;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -16,82 +17,75 @@ use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\CustomCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use App\Repository\UserRepository;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
use function mysql_xdevapi\getSession;
/**
*
*/
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
{
use TargetPathTrait;
/**
* @var \App\Repository\UserRepository
*/
private UserRepository $userRepository;
/**
* @var \Symfony\Component\Routing\RouterInterface
*/
private RouterInterface $router;
public function __construct(UserRepository $userRepository, RouterInterface $router)
{
$this->userRepository = $userRepository;
$this->router = $router;
}
public function authenticate(Request $request): Passport
{
$username = $request->request->get(key: 'username');
$password = $request->request->get(key: 'password');
$csrfToken = $request->request->get(key: '_csrf_token');
$request->getSession()->set(name: Security::LAST_USERNAME, value: $username);
return new Passport(
userBadge: new UserBadge(userIdentifier: $username, userLoader: function ($userIdentifier) {
$user = $this->userRepository->findOneBy(['username' => $userIdentifier]);
if (!$user) {
$user = $this->userRepository->findOneBy(['email' => $userIdentifier]);
}
if (!$user) {
throw new UserNotFoundException();
}
return $user;
}),
credentials: new CustomCredentials(customCredentialsChecker: function ($credentials, User $user) {
return $credentials === 'test';
}, credentials : $password),
// new PasswordCredentials($password),
badges: [
new CsrfTokenBadge(csrfTokenId: 'authenticate', csrfToken: $csrfToken),
new RememberMeBadge()
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($target = $this->getTargetPath(session: $request->getSession(), firewallName: $firewallName)) {
return new RedirectResponse(url: $target);
}
use TargetPathTrait;
return new RedirectResponse(
url: $this->router->generate(name: 'app_main')
);
}
protected function getLoginUrl(Request $request): string
{
return $this->router->generate(name: 'app_login');
}
private UserRepository $userRepository;
private RouterInterface $router;
public function __construct(UserRepository $userRepository, RouterInterface $router)
{
$this->userRepository = $userRepository;
$this->router = $router;
}
public function authenticate(Request $request): Passport
{
$username = $request->request->get(key: 'username');
$password = $request->request->get(key: 'password');
$csrfToken = $request->request->get(key: '_csrf_token');
$request->getSession()->set(name: Security::LAST_USERNAME, value: $username);
return new Passport(
userBadge: new UserBadge(userIdentifier: $username, userLoader: function ($userIdentifier) {
$user = $this->userRepository->findOneBy(['username' => $userIdentifier]);
if (!$user) {
$user = $this->userRepository->findOneBy(['email' => $userIdentifier]);
}
if (!$user) {
throw new UserNotFoundException();
}
return $user;
}),
// remove me later for PasswordCredentials()
credentials: new CustomCredentials(customCredentialsChecker: function ($credentials, User $user) {
return $credentials === 'test';
}, credentials : $password),
// new PasswordCredentials($password),
badges: [
new CsrfTokenBadge(csrfTokenId: 'authenticate', csrfToken: $csrfToken),
new RememberMeBadge(),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($target = $this->getTargetPath(session: $request->getSession(), firewallName: $firewallName)) {
return new RedirectResponse(url: $target);
}
return new RedirectResponse(
url: $this->router->generate(name: 'app_main')
);
}
protected function getLoginUrl(Request $request): string
{
return $this->router->generate(name: 'app_login');
}
}