remove core from app

This commit is contained in:
Simon Vieille 2021-03-20 13:41:15 +01:00
parent fed3c1b3ae
commit 079e52eb42
80 changed files with 88 additions and 4603 deletions

View File

@ -72,7 +72,8 @@
},
"autoload": {
"psr-4": {
"App\\": "src/"
"App\\": "src/",
"App\\Core\\": "core/"
}
},
"autoload-dev": {

View File

@ -17,5 +17,5 @@ return [
Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true],
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
App\Bundle\AppBundle::class => ['all' => true],
App\Core\Bundle\AppBundle::class => ['all' => true],
];

View File

@ -1,7 +1,7 @@
app:
site:
pages:
App\Site\Page\SimplePage:
App\Entity\Page\SimplePage:
name: 'Page simple'
templates:
- {name: "Template 1", file: "site/page/simple/page.html.twig"}

View File

@ -10,17 +10,18 @@ doctrine:
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
auto_mapping: true
mappings:
App\Core\Entity:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/core/Entity'
prefix: 'App\Core\Entity'
alias: App\Core\Entity
App\Entity:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: App\Entity
App\Site\Page:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Site/Page'
prefix: 'App\Site\Page'
gedmo_tree:
type: annotation
prefix: Gedmo\Tree\Entity

View File

@ -26,7 +26,7 @@ security:
check_path: 2fa_login_check # The route name you have used in the routes.yaml
guard:
authenticators:
- App\Authenticator\LoginFormAuthenticator
- App\Core\Authenticator\LoginFormAuthenticator
form_login:
login_path: auth_login
check_path: auth_login

View File

@ -2,6 +2,10 @@ controllers:
resource: ../../src/Controller/
type: annotation
core_controllers:
resource: ../../core/Controller/
type: annotation
kernel:
resource: ../../src/Kernel.php
type: annotation

View File

@ -13,6 +13,11 @@ services:
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\Core\:
resource: '../core/'
exclude:
- '../core/DependencyInjection/'
- '../core/Entity/'
App\:
resource: '../src/'
exclude:
@ -23,12 +28,16 @@ services:
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Core\Controller\:
resource: '../core/Controller/'
tags: ['controller.service_arguments']
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
site.route_loader:
class: App\Router\SiteRouteLoader
class: App\Core\Router\SiteRouteLoader
tags: [routing.loader]
gedmo.listener.tree:

View File

@ -1,96 +0,0 @@
<?php
namespace App\Authenticator;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
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\Http\Util\TargetPathTrait;
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;
private EntityManagerInterface $entityManager;
private UrlGeneratorInterface $urlGenerator;
private CsrfTokenManagerInterface $csrfTokenManager;
private UserPasswordEncoderInterface $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return 'auth_login' === $request->attributes->get('_route') && $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'email' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(Security::LAST_USERNAME, $credentials['email']);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Email could not be found.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('admin_dashboard_index'));
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate('auth_login');
}
}

View File

@ -1,23 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Bundle;
use App\DependencyInjection\AppExtension;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
public function getContainerExtension()
{
return new AppExtension();
}
}

View File

@ -1,153 +0,0 @@
<?php
namespace App\Controller\Account;
use App\Controller\Admin\AdminController;
use App\Manager\EntityManager;
use App\Repository\UserRepository;
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface;
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface as TotpAuthenticatorInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
use ZxcvbnPhp\Zxcvbn;
/**
* @Route("/admin/account")
*/
class AccountAdminController extends AdminController
{
/**
* @Route("/", name="admin_account")
*/
public function account(Request $request, TotpAuthenticatorInterface $totpAuthenticatorService): Response
{
$account = $this->getUser();
return $this->render('account/admin/edit.html.twig', [
'account' => $account,
]);
}
/**
* @Route("/2fa", name="admin_account_2fa")
*/
public function twoFactorAuthentication(
Request $request,
GoogleAuthenticatorInterface $totpAuthenticatorService,
EntityManager $entityManager
): Response {
if ($request->isMethod('GET')) {
return $this->redirectToRoute('admin_account');
}
$account = $this->getUser();
$csrfToken = $request->request->get('_csrf_token');
$enable = (bool) $request->request->get('enable');
$code = $request->request->get('code', '');
$secret = $request->request->get('secret', '');
$qrCodeContent = null;
if ($this->isCsrfTokenValid('2fa', $csrfToken)) {
if ($enable && !$account->isTotpAuthenticationEnabled()) {
if (empty($secret)) {
$secret = $totpAuthenticatorService->generateSecret();
$account->setTotpSecret($secret);
$qrCodeContent = $totpAuthenticatorService->getQRContent($account);
} else {
$account->setTotpSecret($secret);
$qrCodeContent = $totpAuthenticatorService->getQRContent($account);
if (!$totpAuthenticatorService->checkCode($account, $code)) {
$this->addFlash('error', 'Le code n\'est pas valide.');
} else {
$this->addFlash('success', 'Double authentification activée.');
$entityManager->update($account);
return $this->redirectToRoute('admin_account');
}
}
}
if (!$enable && $account->isTotpAuthenticationEnabled()) {
$account->setTotpSecret(null);
$entityManager->update($account);
$this->addFlash('success', 'Double authentification désactivée.');
return $this->redirectToRoute('admin_account');
}
}
return $this->render('account/admin/edit.html.twig', [
'account' => $account,
'twoFaKey' => $secret,
'twoFaQrCodeContent' => $qrCodeContent,
]);
}
/**
* @Route("/password", name="admin_account_password", methods={"POST"})
*/
public function password(
Request $request,
UserRepository $repository,
TokenGeneratorInterface $tokenGenerator,
UserPasswordEncoderInterface $encoder,
EntityManager $entityManager
): Response {
$account = $this->getUser();
$csrfToken = $request->request->get('_csrf_token');
if ($this->isCsrfTokenValid('password', $csrfToken)) {
$password = $request->request->get('password');
if (!$encoder->isPasswordValid($account, $password)) {
$this->addFlash('error', 'Le formulaire n\'est pas valide.');
return $this->redirectToRoute('admin_account');
}
$password1 = $request->request->get('password1');
$password2 = $request->request->get('password2');
$zxcvbn = new Zxcvbn();
$strength = $zxcvbn->passwordStrength($password1, []);
if (4 === $strength['score'] && $password1 === $password2) {
$account
->setPassword($encoder->encodePassword(
$account,
$password1
))
->setConfirmationToken($tokenGenerator->generateToken())
;
$entityManager->update($account);
$this->addFlash('success', 'Mot de passe modifié !');
return $this->redirectToRoute('admin_account');
}
}
$this->addFlash('error', 'Le formulaire n\'est pas valide.');
return $this->redirectToRoute('admin_account');
}
/**
* {@inheritdoc}
*/
protected function getSection(): string
{
return 'account';
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace App\Controller\Admin;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
abstract class AdminController extends AbstractController
{
/**
* {@inheritdoc}
*/
protected function render(string $view, array $parameters = [], Response $response = null): Response
{
$parameters['section'] = $this->getSection();
return parent::render($view, $parameters, $response);
}
abstract protected function getSection(): string;
}

View File

@ -1,159 +0,0 @@
<?php
namespace App\Controller\Auth;
use App\Event\Account\PasswordRequestEvent;
use App\Manager\EntityManager;
use App\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use ZxcvbnPhp\Zxcvbn;
class AuthController extends AbstractController
{
/**
* @Route("/login", name="auth_login")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('admin_dashboard_index');
}
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('auth/login.html.twig', [
'last_username' => $lastUsername,
'error' => $error,
]);
}
/**
* @Route("/resetting/request", name="auth_resetting_request")
*/
public function requestResetting(
Request $request,
UserRepository $repository,
TokenGeneratorInterface $tokenGenerator,
EntityManager $entityManager,
EventDispatcherInterface $eventDispatcher
): Response {
if ($this->getUser()) {
return $this->redirectToRoute('admin_dashboard_index');
}
$emailSent = false;
if ($request->isMethod('POST')) {
$csrfToken = $request->request->get('_csrf_token');
if ($this->isCsrfTokenValid('resetting_request', $csrfToken)) {
$username = trim((string) $request->request->get('username'));
if ($username) {
$account = $repository->findOneByEmail($username);
if ($account) {
$passwordRequestedAt = $account->getPasswordRequestedAt();
if (null !== $passwordRequestedAt && $passwordRequestedAt->getTimestamp() > (time() - 3600 / 2)) {
$emailSent = true;
}
if (!$emailSent) {
$account->setConfirmationToken($tokenGenerator->generateToken());
$account->setPasswordRequestedAt(new \DateTime('now'));
$entityManager->update($account);
$eventDispatcher->dispatch(new PasswordRequestEvent($account), PasswordRequestEvent::EVENT);
$emailSent = true;
}
}
}
}
}
return $this->render('auth/resetting_request.html.twig', [
'email_sent' => $emailSent,
]);
}
/**
* @Route("/resetting/update/{token}", name="auth_resetting_update")
*/
public function requestUpdate(
string $token,
Request $request,
UserRepository $repository,
TokenGeneratorInterface $tokenGenerator,
UserPasswordEncoderInterface $encoder,
EntityManager $entityManager
): Response {
if ($this->getUser()) {
return $this->redirectToRoute('admin_dashboard_index');
}
$account = $repository->findOneByConfirmationToken($token);
$passwordUpdated = false;
$expired = false;
if ($account) {
$passwordRequestedAt = $account->getPasswordRequestedAt();
if (null !== $passwordRequestedAt && $passwordRequestedAt->getTimestamp() < (time() - 3600 * 2)) {
$expired = true;
}
} else {
$expired = true;
}
if ($request->isMethod('POST') && !$expired) {
$csrfToken = $request->request->get('_csrf_token');
if ($this->isCsrfTokenValid('resetting_update', $csrfToken)) {
$password = $request->request->get('password');
$password2 = $request->request->get('password2');
$zxcvbn = new Zxcvbn();
$strength = $zxcvbn->passwordStrength($password, []);
if (4 === $strength['score'] && $password === $password2) {
$account
->setPassword($encoder->encodePassword(
$account,
$password
))
->setConfirmationToken($tokenGenerator->generateToken())
->setPasswordRequestedAt(new \DateTime('now'))
;
$entityManager->update($account);
$passwordUpdated = true;
}
}
}
return $this->render('auth/resetting_update.html.twig', [
'password_updated' => $passwordUpdated,
'token' => $token,
'expired' => $expired,
]);
}
/**
* @Route("/logout", name="auth_logout")
*/
public function logout()
{
throw new \Exception('This method can be blank - it will be intercepted by the logout key on your firewall');
}
}

View File

@ -2,11 +2,11 @@
namespace App\Controller\Blog;
use App\Controller\Admin\AdminController;
use App\Core\Controller\Admin\AdminController;
use App\Entity\Blog\Category as Entity;
use App\Factory\Blog\CategoryFactory as EntityFactory;
use App\Form\Blog\CategoryType as EntityType;
use App\Manager\EntityManager;
use App\Core\Manager\EntityManager;
use App\Repository\Blog\CategoryRepositoryQuery as RepositoryQuery;
use App\Repository\Blog\PostRepositoryQuery;
use Symfony\Component\HttpFoundation\Request;

View File

@ -2,12 +2,12 @@
namespace App\Controller\Blog;
use App\Controller\Admin\AdminController;
use App\Core\Controller\Admin\AdminController;
use App\Entity\Blog\Post as Entity;
use App\Factory\Blog\PostFactory as EntityFactory;
use App\Form\Blog\PostType as EntityType;
use App\Form\FileUploadHandler;
use App\Manager\EntityManager;
use App\Core\Form\FileUploadHandler;
use App\Core\Manager\EntityManager;
use App\Repository\Blog\PostRepositoryQuery as RepositoryQuery;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

View File

@ -1,27 +0,0 @@
<?php
namespace App\Controller\Dashboard;
use App\Controller\Admin\AdminController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin")
*/
class DashboardAdminController extends AdminController
{
/**
* @Route("/", name="admin_dashboard_index")
*/
public function index(): Response
{
return $this->render('dashboard/admin/index.html.twig', [
]);
}
protected function getSection(): string
{
return 'dashboard';
}
}

View File

@ -1,82 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Controller\Admin\AdminController;
use App\Entity\Site\Menu as Entity;
use App\Entity\Site\Navigation;
use App\Factory\Site\MenuFactory as EntityFactory;
use App\Form\Site\MenuType as EntityType;
use App\Manager\EntityManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/site/menu")
*/
class MenuAdminController extends AdminController
{
/**
* @Route("/new/{navigation}", name="admin_site_menu_new", methods={"POST"})
*/
public function new(Navigation $navigation, EntityFactory $factory, EntityManager $entityManager, Request $request): Response
{
$entity = $factory->create($navigation);
$form = $this->createForm(EntityType::class, $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->create($entity);
$this->addFlash('success', 'Donnée enregistrée.');
} else {
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $navigation->getId(),
]);
}
/**
* @Route("/edit/{entity}", name="admin_site_menu_edit", methods={"POST"})
*/
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
$form = $this->createForm(EntityType::class, $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
} else {
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getNavigation()->getId(),
]);
}
/**
* @Route("/delete/{entity}", name="admin_site_menu_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'Données supprimée..');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getNavigation()->getId(),
]);
}
public function getSection(): string
{
return '';
}
}

View File

@ -1,116 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Controller\Admin\AdminController;
use App\Entity\Site\Navigation as Entity;
use App\Factory\Site\NavigationFactory as EntityFactory;
use App\Form\Site\NavigationType as EntityType;
use App\Manager\EntityManager;
use App\Repository\Site\NavigationRepositoryQuery as RepositoryQuery;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/site/navigation")
*/
class NavigationAdminController extends AdminController
{
/**
* @Route("/{page}", name="admin_site_navigation_index", requirements={"page": "\d+"})
*/
public function index(int $page = 1, RepositoryQuery $query, Request $request): Response
{
$pager = $query->paginate($page);
return $this->render('site/navigation_admin/index.html.twig', [
'pager' => $pager,
]);
}
/**
* @Route("/new", name="admin_site_navigation_new")
*/
public function new(EntityFactory $factory, EntityManager $entityManager, Request $request): Response
{
$entity = $factory->create();
$form = $this->createForm(EntityType::class, $entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->create($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_site_navigation_edit', [
'entity' => $entity->getId(),
]);
}
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->render('site/navigation_admin/new.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/edit/{entity}", name="admin_site_navigation_edit")
*/
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
$form = $this->createForm(EntityType::class, $entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_site_navigation_edit', [
'entity' => $entity->getId(),
]);
}
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->render('site/navigation_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/show/{entity}", name="admin_site_navigation_show")
*/
public function show(Entity $entity): Response
{
return $this->render('site/navigation_admin/show.html.twig', [
'entity' => $entity,
]);
}
/**
* @Route("/delete/{entity}", name="admin_site_navigation_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'Données supprimée..');
}
return $this->redirectToRoute('admin_site_navigation_index');
}
public function getSection(): string
{
return 'site_navigation';
}
}

View File

@ -1,263 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Controller\Admin\AdminController;
use App\Entity\Site\Node;
use App\Entity\Site\Node as Entity;
use App\Entity\Site\Page\Page;
use App\Event\EntityManager\EntityManagerEvent;
use App\Factory\Site\NodeFactory as EntityFactory;
use App\Factory\Site\Page\PageFactory;
use App\Form\Site\NodeMoveType;
use App\Form\Site\NodeType as EntityType;
use App\Manager\EntityManager;
use App\Repository\Site\NodeRepository;
use App\Site\PageLocator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/site/node")
*/
class NodeAdminController extends AdminController
{
/**
* @Route("/new/{node}", name="admin_site_node_new")
*/
public function new(
Node $node,
EntityFactory $factory,
PageFactory $pageFactory,
EntityManager $entityManager,
NodeRepository $nodeRepository,
PageLocator $pageLocator,
Request $request
): Response {
$entity = $factory->create($node->getMenu());
$form = $this->createForm(EntityType::class, $entity, [
'pages' => $pageLocator->getPages(),
]);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$position = $form->get('position')->getData();
$parent = 'above' === $position ? $node : $node->getParent();
$entity->setParent($parent);
if ('above' === $position) {
$nodeRepository->persistAsLastChild($entity, $node);
} else {
if ('after' === $position) {
$nodeRepository->persistAsNextSiblingOf($entity, $node);
} elseif ('before' === $position) {
$nodeRepository->persistAsPrevSiblingOf($entity, $node);
}
}
$this->handlePageAssociation(
$form->get('pageAction')->getData(),
$form->get('pageEntity')->getData(),
$form->get('pageType')->getData(),
$entity,
$pageFactory,
$pageLocator
);
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
} else {
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $node->getMenu()->getNavigation()->getId(),
]);
}
return $this->render('site/node_admin/new.html.twig', [
'form' => $form->createView(),
'node' => $node,
'entity' => $entity,
]);
}
/**
* @Route("/edit/{entity}", name="admin_site_node_edit")
*/
public function edit(
Entity $entity,
EntityManager $entityManager,
PageFactory $pageFactory,
PageLocator $pageLocator,
Request $request
): Response {
$form = $this->createForm(EntityType::class, $entity, [
'pages' => $pageLocator->getPages(),
]);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$this->handlePageAssociation(
$form->get('pageAction')->getData(),
$form->get('pageEntity')->getData(),
$form->get('pageType')->getData(),
$entity,
$pageFactory,
$pageLocator
);
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
} else {
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getMenu()->getNavigation()->getId(),
]);
}
return $this->render('site/node_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/move/{entity}", name="admin_site_node_move")
*/
public function move(
Entity $entity,
EntityManager $entityManager,
NodeRepository $nodeRepository,
Request $request
): Response {
$form = $this->createForm(NodeMoveType::class, null, [
'menu' => $entity->getMenu(),
]);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->get('node')->getData()->getId() === $entity->getId()) {
$form->get('node')->addError(new FormError('Élement de référence invalide.'));
}
if ($form->isValid()) {
$position = $form->get('position')->getData();
$node = $form->get('node')->getData();
$parent = 'above' === $position ? $node : $node->getParent();
$entity->setParent($parent);
if ('above' === $position) {
$nodeRepository->persistAsLastChild($entity, $node);
$entityManager->flush();
} else {
if ('after' === $position) {
$nodeRepository->persistAsNextSiblingOf($entity, $node);
} elseif ('before' === $position) {
$nodeRepository->persistAsPrevSiblingOf($entity, $node);
}
$entityManager->flush();
}
$this->addFlash('success', 'Donnée enregistrée.');
} else {
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getMenu()->getNavigation()->getId(),
]);
}
return $this->render('site/node_admin/move.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/toggle/visibility/{entity}", name="admin_site_node_toggle_visibility", methods={"POST"})
*/
public function toggleVisibility(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('toggle_visibility'.$entity->getId(), $request->request->get('_token'))) {
$entity->setIsVisible(!$entity->getIsVisible());
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getMenu()->getNavigation()->getId(),
]);
}
/**
* @Route("/delete/{entity}", name="admin_site_node_delete", methods={"DELETE"})
*/
public function delete(
Entity $entity,
NodeRepository $nodeRepository,
EventDispatcherInterface $eventDispatcher,
Request $request
): Response {
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_DELETE_EVENT);
$nodeRepository->removeFromTree($entity);
$nodeRepository->reorder($entity->getMenu()->getRootNode());
$eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT);
$this->addFlash('success', 'Donnée supprimée.');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $entity->getMenu()->getNavigation()->getId(),
]);
}
public function getSection(): string
{
return '';
}
protected function handlePageAssociation(
string $pageAction,
?Page $pageEntity,
string $pageType,
Entity $entity,
PageFactory $pageFactory,
PageLocator $pageLocator
) {
if ('new' === $pageAction) {
$pageConfiguration = $pageLocator->getPage($pageType);
$page = $pageFactory->create($pageType, $entity->getLabel());
$page->setTemplate($pageConfiguration->getTemplates()[0]['file']);
$entity->setPage($page);
} elseif ('existing' === $pageAction) {
if ($pageEntity) {
$entity->setPage($pageEntity);
} else {
$this->addFlash('info', 'Aucun changement de page effectué.');
}
} elseif ('none' === $pageAction) {
$entity->setPage(null);
}
}
}

View File

@ -1,109 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Controller\Admin\AdminController;
use App\Entity\Site\Page\Page as Entity;
use App\Factory\Site\Page\PageFactory as EntityFactory;
use App\Form\Site\Page\PageType as EntityType;
use App\Manager\EntityManager;
use App\Page\FooPage;
use App\Page\SimplePage;
use App\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
use App\Site\PageLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/site/page")
*/
class PageAdminController extends AdminController
{
/**
* @Route("/{page}", name="admin_site_page_index", requirements={"page": "\d+"})
*/
public function index(int $page = 1, RepositoryQuery $query, Request $request): Response
{
$pager = $query->paginate($page);
return $this->render('site/page_admin/index.html.twig', [
'pager' => $pager,
]);
}
/**
* @Route("/new", name="admin_site_page_new")
*/
public function new(EntityFactory $factory, EntityManager $entityManager): Response
{
// $entity = $factory->create(FooPage::class);
$entity = $factory->create(SimplePage::class);
$entity->setName('Page de test '.mt_rand());
$entityManager->create($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_site_page_edit', [
'entity' => $entity->getId(),
]);
}
/**
* @Route("/edit/{entity}", name="admin_site_page_edit")
*/
public function edit(
int $entity,
EntityFactory $factory,
EntityManager $entityManager,
RepositoryQuery $repositoryQuery,
PageLocator $pageLocator,
Request $request
): Response {
$entity = $repositoryQuery->filterById($entity)->findOne();
$form = $this->createForm(EntityType::class, $entity, [
'pageConfiguration' => $pageLocator->getPage(get_class($entity)),
]);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_site_page_edit', [
'entity' => $entity->getId(),
]);
}
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->render('site/page_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/delete/{entity}", name="admin_site_page_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'Données supprimée..');
}
return $this->redirectToRoute('admin_site_page_index');
}
public function getSection(): string
{
return 'site_page';
}
}

View File

@ -1,25 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Site\SiteRequest;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class PageController extends AbstractController
{
public function show(Request $request, SiteRequest $siteRequest): Response
{
if (!$siteRequest->getPage()) {
throw $this->createNotFoundException();
}
return $this->render($siteRequest->getPage()->getTemplate(), [
'_node' => $siteRequest->getNode(),
'_page' => $siteRequest->getPage(),
'_menu' => $siteRequest->getMenu(),
'_navigation' => $siteRequest->getNavigation(),
]);
}
}

View File

@ -1,66 +0,0 @@
<?php
namespace App\Controller\Site;
use App\Controller\Admin\AdminController;
use App\Entity\Site\Navigation;
use App\Factory\Site\MenuFactory;
use App\Form\Site\MenuType;
use App\Repository\Site\NavigationRepositoryQuery;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/site/tree")
*/
class TreeAdminController extends AdminController
{
/**
* @Route("/", name="admin_site_tree_index")
*/
public function index(NavigationRepositoryQuery $navigationQuery): Response
{
$navigation = $navigationQuery->create()->findOne();
if (null === $navigation) {
$this->addFlash('warning', 'Vous devez ajouter une navigation.');
return $this->redirectToRoute('admin_site_navigation_new');
}
return $this->redirectToRoute('admin_site_tree_navigation', [
'navigation' => $navigation->getId(),
]);
}
/**
* @Route("/navigation/{navigation}", name="admin_site_tree_navigation")
*/
public function navigation(
Navigation $navigation,
NavigationRepositoryQuery $navigationQuery,
MenuFactory $menuFactory
): Response {
$navigations = $navigationQuery->create()->find();
$forms = [
'menu' => $this->createForm(MenuType::class, $menuFactory->create())->createView(),
'menus' => [],
];
foreach ($navigation->getMenus() as $menu) {
$forms['menus'][$menu->getId()] = $this->createForm(MenuType::class, $menu)->createView();
}
return $this->render('site/tree_admin/navigation.html.twig', [
'navigation' => $navigation,
'navigations' => $navigations,
'forms' => $forms,
]);
}
public function getSection(): string
{
return 'site_tree';
}
}

View File

@ -1,157 +0,0 @@
<?php
namespace App\Controller\User;
use App\Controller\Admin\AdminController;
use App\Entity\User as Entity;
use App\Event\Account\PasswordRequestEvent;
use App\Factory\UserFactory as EntityFactory;
use App\Form\UserType as EntityType;
use App\Manager\EntityManager;
use App\Repository\Blog\PostRepositoryQuery;
use App\Repository\UserRepositoryQuery as RepositoryQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
/**
* @Route("/admin/user")
*/
class UserAdminController extends AdminController
{
/**
* @Route("/{page}", name="admin_user_index", requirements={"page": "\d+"})
*/
public function index(int $page = 1, RepositoryQuery $query, Request $request): Response
{
$pager = $query->paginate($page);
return $this->render('user/user_admin/index.html.twig', [
'pager' => $pager,
]);
}
/**
* @Route("/new", name="admin_user_new")
*/
public function new(
EntityFactory $factory,
EntityManager $entityManager,
UserPasswordEncoderInterface $encoder,
Request $request
): Response {
$entity = $factory->create($this->getUser());
$form = $this->createForm(EntityType::class, $entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->create($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_user_edit', [
'entity' => $entity->getId(),
]);
}
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->render('user/user_admin/new.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/edit/{entity}", name="admin_user_edit")
*/
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
$form = $this->createForm(EntityType::class, $entity);
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.');
return $this->redirectToRoute('admin_user_edit', [
'entity' => $entity->getId(),
]);
}
$this->addFlash('warning', 'Le formulaire est invalide.');
}
return $this->render('user/user_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/show/{entity}", name="admin_user_show")
*/
public function show(Entity $entity, PostRepositoryQuery $postQuery): Response
{
$posts = $postQuery->create()
->orderBy('.publishedAt', 'DESC')
->orderBy('.createdAt', 'DESC')
->filterByAuthor($entity)
->paginate(1, 10)
;
return $this->render('user/user_admin/show.html.twig', [
'entity' => $entity,
'posts' => $posts,
]);
}
/**
* @Route("/resetting_request/{entity}", name="admin_user_resetting_request", methods={"POST"})
*/
public function requestResetting(
Entity $entity,
EntityManager $entityManager,
TokenGeneratorInterface $tokenGenerator,
EventDispatcherInterface $eventDispatcher,
Request $request
): Response {
if ($this->isCsrfTokenValid('resetting_request'.$entity->getId(), $request->request->get('_token'))) {
$entity->setConfirmationToken($tokenGenerator->generateToken());
$entity->setPasswordRequestedAt(new \DateTime('now'));
$entityManager->update($entity);
$eventDispatcher->dispatch(new PasswordRequestEvent($entity), PasswordRequestEvent::EVENT);
$this->addFlash('success', 'Demande envoyée.');
}
return $this->redirectToRoute('admin_user_edit', [
'entity' => $entity->getId(),
]);
}
/**
* @Route("/delete/{entity}", name="admin_user_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'Données supprimée..');
}
return $this->redirectToRoute('admin_user_index');
}
public function getSection(): string
{
return 'user';
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class AppExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('app', $config);
}
/**
* {@inheritdoc}
*/
public function getConfiguration(array $configs, ContainerBuilder $container)
{
return new Configuration();
}
}

View File

@ -1,44 +0,0 @@
<?php
namespace App\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('app');
$treeBuilder->getRootNode()
->children()
->arrayNode('site')
->children()
->arrayNode('pages')
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->arrayNode('templates')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('file')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}

View File

@ -2,12 +2,12 @@
namespace App\Entity\Blog;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Core\Doctrine\Timestampable;
use App\Repository\Blog\CategoryRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
/**
* @ORM\Entity(repositoryClass=CategoryRepository::class)

View File

@ -2,13 +2,13 @@
namespace App\Entity\Blog;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Core\Doctrine\Timestampable;
use App\Entity\User;
use App\Repository\Blog\PostRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
/**
* @ORM\Entity(repositoryClass=PostRepository::class)

View File

@ -1,7 +0,0 @@
<?php
namespace App\Entity;
interface EntityInterface
{
}

View File

@ -1,9 +1,9 @@
<?php
namespace App\Site\Page;
namespace App\Entity\Page;
use App\Entity\Site\Page\Block;
use App\Entity\Site\Page\Page;
use App\Core\Entity\Site\Page\Block;
use App\Core\Entity\Site\Page\Page;
use App\Form\Site\Page\TextareaBlockType;
use App\Form\Site\Page\TextBlockType;
use Doctrine\ORM\Mapping as ORM;

View File

@ -1,146 +0,0 @@
<?php
namespace App\Entity\Site;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Repository\Site\MenuRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=MenuRepository::class)
* @ORM\HasLifecycleCallbacks
*/
class Menu implements EntityInterface
{
use Timestampable;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $label;
/**
* @ORM\Column(type="string", length=255)
*/
private $code;
/**
* @ORM\ManyToOne(targetEntity=Navigation::class, inversedBy="menus")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
*/
private $navigation;
/**
* @ORM\OneToMany(targetEntity=Node::class, mappedBy="menu", orphanRemoval=true, cascade={"remove", "persist"})
*/
private $nodes;
/**
* @ORM\OneToOne(targetEntity=Node::class, cascade={"persist"})
* @ORM\JoinColumn(onDelete="CASCADE")
*/
private $rootNode;
public function __construct()
{
$this->nodes = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(string $label): self
{
$this->label = $label;
return $this;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getNavigation(): ?Navigation
{
return $this->navigation;
}
public function setNavigation(?Navigation $navigation): self
{
$this->navigation = $navigation;
return $this;
}
/**
* @return Collection|Node[]
*/
public function getNodes(): Collection
{
return $this->nodes;
}
public function addNode(Node $node): self
{
if (!$this->nodes->contains($node)) {
$this->nodes[] = $node;
$node->setMenu($this);
}
return $this;
}
public function removeNode(Node $node): self
{
if ($this->nodes->removeElement($node)) {
// set the owning side to null (unless already changed)
if ($node->getMenu() === $this) {
$node->setMenu(null);
}
}
return $this;
}
public function getRootNode(): ?Node
{
return $this->rootNode;
}
public function setRootNode(?Node $rootNode): self
{
$this->rootNode = $rootNode;
return $this;
}
public function getRouteName(): string
{
return $this->getNavigation()->getRouteName().'_'.($this->getCode() ? $this->getCode() : $this->getId());
}
}

View File

@ -1,127 +0,0 @@
<?php
namespace App\Entity\Site;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Repository\Site\NavigationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=NavigationRepository::class)
* @ORM\HasLifecycleCallbacks
*/
class Navigation implements EntityInterface
{
use Timestampable;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $label;
/**
* @ORM\Column(type="string", length=255)
*/
private $code;
/**
* @ORM\Column(type="string", length=255)
*/
private $domain;
/**
* @ORM\OneToMany(targetEntity=Menu::class, mappedBy="navigation")
*/
private $menus;
public function __construct()
{
$this->menus = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(string $label): self
{
$this->label = $label;
return $this;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getDomain(): ?string
{
return $this->domain;
}
public function setDomain(string $domain): self
{
$this->domain = $domain;
return $this;
}
/**
* @return Collection|Menu[]
*/
public function getMenus(): Collection
{
return $this->menus;
}
public function addMenu(Menu $menu): self
{
if (!$this->menus->contains($menu)) {
$this->menus[] = $menu;
$menu->setNavigation($this);
}
return $this;
}
public function removeMenu(Menu $menu): self
{
if ($this->menus->removeElement($menu)) {
// set the owning side to null (unless already changed)
if ($menu->getNavigation() === $this) {
$menu->setNavigation(null);
}
}
return $this;
}
public function getRouteName(): string
{
return $this->getCode() ? $this->getCode() : 'navigation_'.$this->getId();
}
}

View File

@ -1,304 +0,0 @@
<?php
namespace App\Entity\Site;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Entity\Site\Page\Page;
use App\Repository\Site\NodeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @Gedmo\Tree(type="nested")
* @ORM\HasLifecycleCallbacks
* @ORM\Entity(repositoryClass=NodeRepository::class)
*/
class Node implements EntityInterface
{
use Timestampable;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Menu::class, inversedBy="nodes", cascade={"persist", "remove"})
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
*/
private $menu;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $label;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $url;
/**
* @ORM\Column(type="boolean", options={"default"=0})
*/
private $isVisible = false;
/**
* @Gedmo\TreeLeft
* @ORM\Column(type="integer")
*/
private $treeLeft;
/**
* @Gedmo\TreeLevel
* @ORM\Column(type="integer")
*/
private $treeLevel;
/**
* @Gedmo\TreeRight
* @ORM\Column(type="integer")
*/
private $treeRight;
/**
* @Gedmo\TreeRoot
* @ORM\ManyToOne(targetEntity="Node")
* @ORM\JoinColumn(referencedColumnName="id", onDelete="CASCADE")
*/
private $treeRoot;
/**
* @Gedmo\TreeParent
* @ORM\ManyToOne(targetEntity="Node", inversedBy="children")
* @ORM\JoinColumn(referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Node", mappedBy="parent")
* @ORM\OrderBy({"treeLeft"="ASC"})
*/
private $children;
/**
* @ORM\ManyToOne(targetEntity=Page::class, inversedBy="nodes", cascade={"persist"})
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $page;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $code;
public function __construct()
{
$this->children = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getMenu(): ?Menu
{
return $this->menu;
}
public function setMenu(?Menu $menu): self
{
$this->menu = $menu;
return $this;
}
public function getTreeLeft(): ?int
{
return $this->treeLeft;
}
public function setTreeLeft(int $treeLeft): self
{
$this->treeLeft = $treeLeft;
return $this;
}
public function getTreeLevel(): ?int
{
return $this->treeLevel;
}
public function setTreeLevel(int $treeLevel): self
{
$this->treeLevel = $treeLevel;
return $this;
}
public function getTreeRight(): ?int
{
return $this->treeRight;
}
public function setTreeRight(int $treeRight): self
{
$this->treeRight = $treeRight;
return $this;
}
public function getTreeRoot(): ?self
{
return $this->treeRoot;
}
public function setTreeRoot(?self $treeRoot): self
{
$this->treeRoot = $treeRoot;
return $this;
}
public function getParent(): ?self
{
return $this->parent;
}
public function setParent(?self $parent): self
{
$this->parent = $parent;
return $this;
}
/**
* @return Collection|Node[]
*/
public function getChildren(): Collection
{
return $this->children;
}
public function addChild(Node $child): self
{
if (!$this->children->contains($child)) {
$this->children[] = $child;
$child->setParent($this);
}
return $this;
}
public function removeChild(Node $child): self
{
if ($this->children->removeElement($child)) {
// set the owning side to null (unless already changed)
if ($child->getParent() === $this) {
$child->setParent(null);
}
}
return $this;
}
public function getAllChildren(): ArrayCollection
{
$children = [];
$getChildren = function (Node $node) use (&$children, &$getChildren) {
foreach ($node->getChildren() as $nodeChildren) {
$children[] = $nodeChildren;
$getChildren($nodeChildren);
}
};
$getChildren($this);
usort($children, function ($a, $b) {
return $a->getTreeLeft() < $b->getTreeLeft() ? -1 : 1;
});
return new ArrayCollection($children);
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(?string $label): self
{
$this->label = $label;
return $this;
}
public function getUrl(): ?string
{
return $this->url;
}
public function setUrl(?string $url): self
{
$this->url = $url;
return $this;
}
public function getIsVisible(): ?bool
{
return $this->isVisible;
}
public function setIsVisible(bool $isVisible): self
{
$this->isVisible = $isVisible;
return $this;
}
public function getTreeLabel()
{
$prefix = str_repeat('-', ($this->getTreeLevel() - 1) * 5);
return trim($prefix.' '.$this->getLabel());
}
public function getPage(): ?Page
{
return $this->page;
}
public function setPage(?Page $page): self
{
$this->page = $page;
return $this;
}
public function getRouteName(): string
{
return $this->getMenu()->getRouteName().'_'.($this->getCode() ? $this->getCode() : $this->getId());
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(?string $code): self
{
$this->code = $code;
return $this;
}
}

View File

@ -1,80 +0,0 @@
<?php
namespace App\Entity\Site\Page;
use App\Doctrine\Timestampable;
use App\Repository\Site\Page\BlockRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=BlockRepository::class)
* @ORM\HasLifecycleCallbacks
*/
class Block
{
use Timestampable;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $value;
/**
* @ORM\ManyToOne(targetEntity=Page::class, inversedBy="blocks")
* @ORM\JoinColumn(onDelete="CASCADE")
*/
private $page;
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 getValue(): ?string
{
return $this->value;
}
public function setValue(string $value): self
{
$this->value = $value;
return $this;
}
public function getPage(): ?Page
{
return $this->page;
}
public function setPage(?Page $page): self
{
$this->page = $page;
return $this;
}
}

View File

@ -1,248 +0,0 @@
<?php
namespace App\Entity\Site\Page;
use App\Doctrine\Timestampable;
use App\Entity\EntityInterface;
use App\Entity\Site\Node;
use App\Repository\Site\Page\PageRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Form\FormBuilderInterface;
/**
* @ORM\Entity(repositoryClass=PageRepository::class)
* @ORM\DiscriminatorColumn(name="class_key", type="string")
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\HasLifecycleCallbacks
*/
class Page implements EntityInterface
{
use Timestampable;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $template;
/**
* @ORM\OneToMany(targetEntity=Block::class, mappedBy="page", cascade={"persist"})
*/
private $blocks;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $metaTitle;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $metaDescrition;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $ogTitle;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $ogDescription;
/**
* @ORM\OneToMany(targetEntity=Node::class, mappedBy="page")
*/
private $nodes;
public function __construct()
{
$this->blocks = new ArrayCollection();
$this->nodes = new ArrayCollection();
}
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 getTemplate(): ?string
{
return $this->template;
}
public function setTemplate(?string $template): self
{
$this->template = $template;
return $this;
}
/**
* @return Collection|Block[]
*/
public function getBlocks(): Collection
{
return $this->blocks;
}
public function addBlock(Block $block): self
{
if (!$this->blocks->contains($block)) {
$this->blocks[] = $block;
$block->setPage($this);
}
return $this;
}
public function removeBlock(Block $block): self
{
if ($this->blocks->removeElement($block)) {
// set the owning side to null (unless already changed)
if ($block->getPage() === $this) {
$block->setPage(null);
}
}
return $this;
}
public function buildForm(FormBuilderInterface $builder)
{
}
public function getBlock($name)
{
foreach ($this->getBlocks() as $block) {
if ($block->getName() === $name) {
return $block;
}
}
$block = new Block();
$block->setName($name);
$block->setPage($this);
return $block;
}
public function setBlock(Block $block): self
{
foreach ($this->blocks->toArray() as $key => $value) {
if ($value->getName() === $block->getName()) {
$this->blocks->remove($key);
$this->blocks->add($block);
return $this;
}
}
$this->blocks->add($block);
return $this;
}
public function getMetaTitle(): ?string
{
return $this->metaTitle;
}
public function setMetaTitle(?string $metaTitle): self
{
$this->metaTitle = $metaTitle;
return $this;
}
public function getMetaDescrition(): ?string
{
return $this->metaDescrition;
}
public function setMetaDescrition(?string $metaDescrition): self
{
$this->metaDescrition = $metaDescrition;
return $this;
}
public function getOgTitle(): ?string
{
return $this->ogTitle;
}
public function setOgTitle(?string $ogTitle): self
{
$this->ogTitle = $ogTitle;
return $this;
}
public function getOgDescription(): ?string
{
return $this->ogDescription;
}
public function setOgDescription(?string $ogDescription): self
{
$this->ogDescription = $ogDescription;
return $this;
}
/**
* @return Collection|Node[]
*/
public function getNodes(): Collection
{
return $this->nodes;
}
public function addNode(Node $node): self
{
if (!$this->nodes->contains($node)) {
$this->nodes[] = $node;
$node->setPage($this);
}
return $this;
}
public function removeNode(Node $node): self
{
if ($this->nodes->removeElement($node)) {
// set the owning side to null (unless already changed)
if ($node->getPage() === $this) {
$node->setPage(null);
}
}
return $this;
}
}

View File

@ -2,18 +2,19 @@
namespace App\Entity;
use App\Doctrine\Timestampable;
use App\Entity\Blog\Post;
use App\Core\Doctrine\Timestampable;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use App\Core\Entity\EntityInterface;
use App\Entity\Blog\Post;
/**
* @ORM\Entity(repositoryClass=UserRepository::class)
* @ORM\HasLifecycleCallbacks
* @ORM\HasLifecycleCallbacks()
*/
class User implements UserInterface, TwoFactorInterface, EntityInterface
{
@ -66,21 +67,51 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
*/
private $isAdmin;
/**
* @ORM\OneToMany(targetEntity=Post::class, mappedBy="author")
*/
private $posts;
/**
* @ORM\Column(type="boolean", options={"default"=0})
*/
private $isWriter;
/**
* @ORM\OneToMany(targetEntity=Post::class, mappedBy="author")
*/
private $posts;
public function __construct()
{
$this->posts = new ArrayCollection();
}
/**
* @return Collection|Post[]
*/
public function getPosts(): Collection
{
return $this->posts;
}
public function addPost(Post $post): self
{
if (!$this->posts->contains($post)) {
$this->posts[] = $post;
$post->setAuthor($this);
}
return $this;
}
public function removePost(Post $post): self
{
if ($this->posts->removeElement($post)) {
// set the owning side to null (unless already changed)
if ($post->getAuthor() === $this) {
$post->setAuthor(null);
}
}
return $this;
}
public function getId(): ?int
{
return $this->id;
@ -113,6 +144,8 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
*/
public function getRoles(): array
{
$roles = [];
if ($this->getIsWriter()) {
$roles[] = 'ROLE_WRITER';
}
@ -251,36 +284,6 @@ class User implements UserInterface, TwoFactorInterface, EntityInterface
return $this;
}
/**
* @return Collection|Post[]
*/
public function getPosts(): Collection
{
return $this->posts;
}
public function addPost(Post $post): self
{
if (!$this->posts->contains($post)) {
$this->posts[] = $post;
$post->setAuthor($this);
}
return $this;
}
public function removePost(Post $post): self
{
if ($this->posts->removeElement($post)) {
// set the owning side to null (unless already changed)
if ($post->getAuthor() === $this) {
$post->setAuthor(null);
}
}
return $this;
}
public function getIsWriter(): ?bool
{
return $this->isWriter;

View File

@ -1,28 +0,0 @@
<?php
namespace App\Event\Account;
use App\Entity\User;
use Symfony\Contracts\EventDispatcher\Event;
/**
* class PasswordRequestEvent.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PasswordRequestEvent extends Event
{
const EVENT = 'account_event.password_request';
protected User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function getUser(): USer
{
return $this->user;
}
}

View File

@ -1,33 +0,0 @@
<?php
namespace App\Event\EntityManager;
use App\Entity\EntityInterface;
use Symfony\Contracts\EventDispatcher\Event;
/**
* class EntityEvent.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class EntityManagerEvent extends Event
{
const CREATE_EVENT = 'entity_manager_event.create';
const UPDATE_EVENT = 'entity_manager_event.update';
const DELETE_EVENT = 'entity_manager_event.delete';
const PRE_CREATE_EVENT = 'entity_manager_event.pre_create';
const PRE_UPDATE_EVENT = 'entity_manager_event.pre_update';
const PRE_DELETE_EVENT = 'entity_manager_event.pre_delete';
protected EntityInterface $entity;
public function __construct(EntityInterface $entity)
{
$this->entity = $entity;
}
public function getEntity(): EntityInterface
{
return $this->entity;
}
}

View File

@ -1,50 +0,0 @@
<?php
namespace App\EventSuscriber\Account;
use App\Event\Account\PasswordRequestEvent;
use App\Notification\MailNotifier;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* class EventListener.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PasswordRequestEventSubscriber implements EventSubscriberInterface
{
protected MailNotifier $notifier;
protected UrlGeneratorInterface $urlGenerator;
public function __construct(MailNotifier $notifier, UrlGeneratorInterface $urlGenerator)
{
$this->notifier = $notifier;
$this->urlGenerator = $urlGenerator;
}
public static function getSubscribedEvents()
{
return [
PasswordRequestEvent::EVENT => 'onRequest',
];
}
public function onRequest(PasswordRequestEvent $event)
{
$this->notifier
->setFrom('system@tinternet.net')
->setSubject('[Tinternet & cie] Mot de passe perdu')
->addRecipient($event->getUser()->getEmail())
->notify('resetting_request', [
'reseting_update_link' => $this->urlGenerator->generate(
'auth_resetting_update',
[
'token' => $event->getUser()->getConfirmationToken(),
],
UrlGeneratorInterface::ABSOLUTE_URL
),
])
;
}
}

View File

@ -3,9 +3,9 @@
namespace App\EventSuscriber\Blog;
use App\Entity\Blog\Post;
use App\Entity\EntityInterface;
use App\Event\EntityManager\EntityManagerEvent;
use App\EventSuscriber\EntityManagerEventSubscriber;
use App\Core\Entity\EntityInterface;
use App\Core\Event\EntityManager\EntityManagerEvent;
use App\Core\EventSuscriber\EntityManagerEventSubscriber;
use App\Repository\Blog\PostRepositoryQuery;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;

View File

@ -1,50 +0,0 @@
<?php
namespace App\EventSuscriber;
use App\Event\EntityManager\EntityManagerEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* class EntityManagerEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
abstract class EntityManagerEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
EntityManagerEvent::CREATE_EVENT => 'onCreate',
EntityManagerEvent::UPDATE_EVENT => 'onUpdate',
EntityManagerEvent::DELETE_EVENT => 'onDelete',
EntityManagerEvent::PRE_CREATE_EVENT => 'onPreCreate',
EntityManagerEvent::PRE_UPDATE_EVENT => 'onPreUpdate',
EntityManagerEvent::PRE_DELETE_EVENT => 'onPreDelete',
];
}
public function onCreate(EntityManagerEvent $event)
{
}
public function onUpdate(EntityManagerEvent $event)
{
}
public function onDelete(EntityManagerEvent $event)
{
}
public function onPreCreate(EntityManagerEvent $event)
{
}
public function onPreUpdate(EntityManagerEvent $event)
{
}
public function onPreDelete(EntityManagerEvent $event)
{
}
}

View File

@ -1,92 +0,0 @@
<?php
namespace App\EventSuscriber\Site;
use App\Entity\EntityInterface;
use App\Entity\Site\Menu;
use App\Event\EntityManager\EntityManagerEvent;
use App\EventSuscriber\EntityManagerEventSubscriber;
use App\Factory\Site\NodeFactory;
use App\Manager\EntityManager;
use App\Repository\Site\NodeRepository;
use App\Slugify\CodeSlugify;
/**
* class MenuEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class MenuEventSubscriber extends EntityManagerEventSubscriber
{
protected NodeFactory $nodeFactory;
protected NodeRepository $nodeRepository;
protected EntityManager $entityManager;
protected CodeSlugify $slugify;
public function __construct(
NodeFactory $nodeFactory,
NodeRepository $nodeRepository,
EntityManager $entityManager,
CodeSlugify $slugify
) {
$this->nodeFactory = $nodeFactory;
$this->nodeRepository = $nodeRepository;
$this->entityManager = $entityManager;
$this->slugify = $slugify;
}
public function support(EntityInterface $entity)
{
return $entity instanceof Menu;
}
public function onPreUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$menu = $event->getEntity();
$menu->setCode($this->slugify->slugify($menu->getCode()));
}
public function onCreate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$menu = $event->getEntity();
if (0 !== count($menu->getNodes())) {
return;
}
$rootNode = $this->nodeFactory->create($menu);
$childNode = $this->nodeFactory->create($menu, '/');
$childNode
->setParent($rootNode)
->setLabel('Premier élément')
;
$menu->setRootNode($rootNode);
$this->entityManager->getEntityManager()->persist($rootNode);
$this->entityManager->getEntityManager()->persist($childNode);
$this->entityManager->getEntityManager()->persist($menu);
$this->entityManager->flush();
$this->nodeRepository->persistAsFirstChild($childNode, $rootNode);
}
public function onUpdate(EntityManagerEvent $event)
{
return $this->onCreate($event);
}
public function onPreCreate(EntityManagerEvent $event)
{
return $this->onPreUpdate($event);
}
}

View File

@ -1,46 +0,0 @@
<?php
namespace App\EventSuscriber\Site;
use App\Entity\EntityInterface;
use App\Entity\Site\Navigation;
use App\Event\EntityManager\EntityManagerEvent;
use App\EventSuscriber\EntityManagerEventSubscriber;
use App\Manager\EntityManager;
use App\Slugify\CodeSlugify;
/**
* class NavigationEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationEventSubscriber extends EntityManagerEventSubscriber
{
public function __construct(
EntityManager $entityManager,
CodeSlugify $slugify
) {
$this->entityManager = $entityManager;
$this->slugify = $slugify;
}
public function support(EntityInterface $entity)
{
return $entity instanceof Navigation;
}
public function onPreUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$menu = $event->getEntity();
$menu->setCode($this->slugify->slugify($menu->getCode()));
}
public function onPreCreate(EntityManagerEvent $event)
{
return $this->onPreUpdate($event);
}
}

View File

@ -1,109 +0,0 @@
<?php
namespace App\EventSuscriber\Site;
use App\Entity\EntityInterface;
use App\Entity\Site\Node;
use App\Event\EntityManager\EntityManagerEvent;
use App\EventSuscriber\EntityManagerEventSubscriber;
use App\Factory\Site\NodeFactory;
use App\Manager\EntityManager;
use App\Repository\Site\NodeRepository;
use App\Slugify\Slugify;
use Symfony\Component\HttpKernel\KernelInterface;
/**
* class NodeEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NodeEventSubscriber extends EntityManagerEventSubscriber
{
protected NodeFactory $nodeFactory;
protected EntityManager $entityManager;
protected KernelInterface $kernel;
protected Slugify $slugify;
public function __construct(
NodeFactory $nodeFactory,
NodeRepository $nodeRepository,
EntityManager $entityManager,
Slugify $slugify
) {
$this->nodeFactory = $nodeFactory;
$this->nodeRepository = $nodeRepository;
$this->entityManager = $entityManager;
$this->slugify = $slugify;
}
public function support(EntityInterface $entity)
{
return $entity instanceof Node;
}
public function onPreUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$node = $event->getEntity();
if ($node->getUrl()) {
$generatedUrl = $node->getUrl();
} else {
$path = [];
$parent = $node->getParent();
if ($parent && $parent->getUrl()) {
$pPath = trim($parent->getUrl(), '/');
if ($pPath) {
$path[] = $pPath;
}
}
$path[] = $this->slugify->slugify($node->getLabel());
$generatedUrl = '/'.implode('/', $path);
}
$urlExists = $this->nodeRepository->urlExists($generatedUrl, $node);
if ($urlExists) {
$number = 1;
while ($this->nodeRepository->urlExists($generatedUrl.'-'.$number, $node)) {
++$number;
}
$generatedUrl = $generatedUrl.'-'.$number;
}
$node->setUrl($generatedUrl);
}
public function onDelete(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$menu = $event->getEntity()->getMenu();
$rootNode = $menu->getRootNode();
if (0 !== count($rootNode->getChildren())) {
return;
}
$childNode = $this->nodeFactory->create($menu);
$childNode
->setParent($rootNode)
->setLabel('Premier élément')
;
$this->entityManager->update($rootNode, false);
$this->entityManager->create($childNode, false);
$this->nodeRepository->persistAsFirstChild($childNode, $rootNode);
}
}

View File

@ -1,70 +0,0 @@
<?php
namespace App\EventSuscriber\Site;
use App\Entity\EntityInterface;
use App\Entity\Site\Node;
use App\Event\EntityManager\EntityManagerEvent;
use App\EventSuscriber\EntityManagerEventSubscriber;
use App\Factory\Site\NodeFactory;
use App\Manager\EntityManager;
use App\Repository\Site\NodeRepository;
use App\Slugify\Slugify;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpKernel\KernelInterface;
use App\Entity\Site\Menu;
use App\Entity\Site\Navigation;
/**
* class SiteEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class SiteEventSubscriber extends EntityManagerEventSubscriber
{
protected KernelInterface $kernel;
public function __construct(KernelInterface $kernel) {
$this->kernel = $kernel;
}
public function support(EntityInterface $entity)
{
return $entity instanceof Node || $entity instanceof Menu || $entity instanceof Navigation;
}
protected function cleanCache()
{
$application = new Application($this->kernel);
$application->setAutoExit(false);
$input = new ArrayInput([
'command' => 'cache:clear',
]);
$output = new BufferedOutput();
$application->run($input, $output);
}
public function onUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
$this->cleanCache();
}
public function onCreate(EntityManagerEvent $event)
{
return $this->onUpdate($event);
}
public function onDelete(EntityManagerEvent $event)
{
return $this->onUpdate($event);
}
}

View File

@ -1,25 +0,0 @@
<?php
namespace App\Factory\Site;
use App\Entity\Site\Menu;
use App\Entity\Site\Navigation;
/**
* class MenuFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class MenuFactory
{
public function create(?Navigation $navigation = null): Menu
{
$entity = new Menu();
if (null !== $navigation) {
$entity->setNavigation($navigation);
}
return $entity;
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace App\Factory\Site;
use App\Entity\Site\Navigation;
/**
* class NavigationFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationFactory
{
public function create(): Navigation
{
return new Navigation();
}
}

View File

@ -1,30 +0,0 @@
<?php
namespace App\Factory\Site;
use App\Entity\Site\Menu;
use App\Entity\Site\Node;
/**
* class NodeFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NodeFactory
{
public function create(?Menu $menu = null, string $url = null): Node
{
$entity = new Node();
if (null !== $menu) {
$entity->setMenu($menu);
}
if (null !== $url) {
$entity->setUrl($url);
}
return $entity;
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace App\Factory\Site\Page;
use App\Entity\Site\Page\Page;
/**
* class PageFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageFactory
{
public function create(string $className, string $name): Page
{
$entity = new $className();
$entity->setName($name);
return $entity;
}
}

View File

@ -5,32 +5,13 @@ namespace App\Factory;
use App\Entity\User;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
use App\Core\Factory\UserFactory as BaseUserFactory;
/**
* class UserFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class UserFactory
class UserFactory extends BaseUserFactory
{
protected TokenGeneratorInterface $tokenGenerator;
protected UserPasswordEncoderInterface $encoder;
public function __construct(TokenGeneratorInterface $tokenGenerator, UserPasswordEncoderInterface $encoder)
{
$this->tokenGenerator = $tokenGenerator;
$this->encoder = $encoder;
}
public function create(): User
{
$entity = new User();
$entity->setPassword($this->encoder->encodePassword(
$entity,
$this->tokenGenerator->generateToken()
));
return $entity;
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace App\Form;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
* class FileUploadHandler.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class FileUploadHandler
{
public function handleForm(?UploadedFile $uploadedFile, string $path, callable $afterUploadCallback): void
{
if (null === $uploadedFile) {
return;
}
$originalFilename = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME);
$safeFilename = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
$filename = date('Ymd-his').$safeFilename.'.'.$uploadedFile->guessExtension();
$uploadedFile->move($path, $filename);
$afterUploadCallback($filename);
}
}

View File

@ -1,51 +0,0 @@
<?php
namespace App\Form\Site;
use App\Entity\Site\Menu;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class MenuType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'label',
TextType::class,
[
'label' => 'Libellé',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'code',
TextType::class,
[
'label' => 'Code',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Menu::class,
]);
}
}

View File

@ -1,65 +0,0 @@
<?php
namespace App\Form\Site;
use App\Entity\Site\Navigation;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class NavigationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'label',
TextType::class,
[
'label' => 'Libellé',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'code',
TextType::class,
[
'label' => 'Code',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'domain',
TextType::class,
[
'label' => 'Nom de domaine',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Navigation::class,
]);
}
}

View File

@ -1,62 +0,0 @@
<?php
namespace App\Form\Site;
use App\Entity\Site\Node;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class NodeMoveType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'position',
ChoiceType::class,
[
'label' => 'Position',
'required' => true,
'choices' => [
'Après' => 'after',
'Avant' => 'before',
'En dessous' => 'above',
],
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'node',
EntityType::class,
[
'label' => 'Élement de référence',
'class' => Node::class,
'choices' => call_user_func(function () use ($options) {
return $options['menu']->getRootNode()->getAllChildren();
}),
'choice_label' => 'treeLabel',
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => null,
'menu' => null,
]);
}
}

View File

@ -1,158 +0,0 @@
<?php
namespace App\Form\Site;
use App\Entity\Site\Node;
use App\Entity\Site\Page\Page;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class NodeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'label',
TextType::class,
[
'label' => 'Libellé',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'url',
TextType::class,
[
'label' => 'URL',
'required' => false,
'help' => 'Laisser vide pour une génération automatique',
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'code',
TextType::class,
[
'label' => 'Code',
'required' => false,
'help' => 'Sans espace, en minusule, sans caractère spécial',
'attr' => [
],
'constraints' => [
],
]
);
$actions = [
'Nouvelle page' => 'new',
'Associer à une page existante' => 'existing',
'Aucune page' => 'none',
];
if ($builder->getData()->getId()) {
$actions['Garder la configuration actuelle'] = 'keep';
}
$builder->add(
'pageAction',
ChoiceType::class,
[
'label' => false,
'required' => true,
'expanded' => true,
'mapped' => false,
'choices' => $actions,
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'pageType',
ChoiceType::class,
[
'label' => false,
'required' => true,
'mapped' => false,
'choices' => call_user_func(function () use ($options) {
$choices = [];
foreach ($options['pages'] as $page) {
$choices[$page->getName()] = $page->getClassName();
}
return $choices;
}),
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'pageEntity',
EntityType::class,
[
'label' => false,
'required' => true,
'mapped' => false,
'class' => Page::class,
'choice_label' => 'name',
'query_builder' => function (EntityRepository $repo) {
return $repo->createQueryBuilder('p')
->orderBy('p.name', 'ASC')
;
},
'constraints' => [
],
]
);
if (null === $builder->getData()->getId()) {
$builder->add(
'position',
ChoiceType::class,
[
'label' => 'Position',
'required' => true,
'mapped' => false,
'choices' => [
'Après' => 'after',
'Avant' => 'before',
'En dessous' => 'above',
],
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Node::class,
'pages' => [],
]);
}
}

View File

@ -1,116 +0,0 @@
<?php
namespace App\Form\Site\Page;
use App\Entity\Site\Page\Page;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class PageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'name',
TextType::class,
[
'label' => 'Nom',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'metaTitle',
TextType::class,
[
'label' => 'Titre',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'metaDescrition',
TextType::class,
[
'label' => 'Description',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'ogTitle',
TextType::class,
[
'label' => 'Titre',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'ogDescription',
TextType::class,
[
'label' => 'Description',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'template',
ChoiceType::class,
[
'label' => 'Rendu',
'required' => true,
'choices' => call_user_func(function () use ($options) {
$choices = [];
foreach ($options['pageConfiguration']->getTemplates() as $template) {
$choices[$template['name']] = $template['file'];
}
return $choices;
}),
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->getData()->buildForm($builder);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Page::class,
'pageConfiguration' => null,
]);
}
}

View File

@ -1,32 +0,0 @@
<?php
namespace App\Form\Site\Page;
use App\Entity\Site\Page\Block;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class TextBlockType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'value',
TextType::class,
array_merge([
'required' => false,
'label' => false,
], $options['options']),
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Block::class,
'options' => [],
]);
}
}

View File

@ -1,21 +0,0 @@
<?php
namespace App\Form\Site\Page;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
class TextareaBlockType extends TextBlockType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'value',
TextareaType::class,
array_merge([
'required' => false,
'label' => false,
], $options['options']),
);
}
}

View File

@ -10,82 +10,8 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use App\Core\Form\UserType as BaseUserType;
class UserType extends AbstractType
class UserType extends BaseUserType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'email',
EmailType::class,
[
'label' => 'E-mail',
'required' => true,
'attr' => [
],
'constraints' => [
new Email(),
],
]
);
$builder->add(
'displayName',
TextType::class,
[
'label' => 'Nom complet',
'required' => true,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'displayName',
TextType::class,
[
'label' => 'Nom complet',
'required' => true,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'isAdmin',
CheckboxType::class,
[
'label' => 'Administrateur⋅trice',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
$builder->add(
'isWriter',
CheckboxType::class,
[
'label' => 'Rédacteur⋅trice',
'required' => false,
'attr' => [
],
'constraints' => [
],
]
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}

View File

@ -1,98 +0,0 @@
<?php
namespace App\Manager;
use App\Entity\EntityInterface;
use App\Event\EntityManager\EntityManagerEvent;
use Doctrine\ORM\EntityManager as DoctrineEntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* class EntityManager.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class EntityManager
{
protected EventDispatcherInterface $eventDispatcher;
protected DoctrineEntityManager $entityManager;
public function __construct(EventDispatcherInterface $eventDispatcher, EntityManagerInterface $entityManager)
{
$this->eventDispatcher = $eventDispatcher;
$this->entityManager = $entityManager;
}
public function create(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_CREATE_EVENT);
}
$this->persist($entity);
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT);
}
return $this;
}
public function update(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_UPDATE_EVENT);
}
$this->persist($entity);
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT);
}
return $this;
}
public function delete(EntityInterface $entity, bool $dispatchEvent = true): self
{
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::PRE_DELETE_EVENT);
}
$this->entityManager->remove($entity);
$this->flush();
if ($dispatchEvent) {
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT);
}
return $this;
}
public function flush(): self
{
$this->entityManager->flush();
return $this;
}
public function clear(): self
{
$this->entityManager->clear();
return $this;
}
public function getEntityManager(): EntityManagerInterface
{
return $this->entityManager;
}
protected function persist(EntityInterface $entity)
{
$this->entityManager->persist($entity);
$this->flush();
}
}

View File

@ -1,338 +0,0 @@
<?php
namespace App\Notification;
use Swift_Attachment;
use Swift_Mailer;
use Swift_Message;
use Twig\Environment as TwigEnvironment;
/**
* class MailNotifier.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class MailNotifier
{
/**
* @var Swift_Mailer
*/
protected $mailer;
/**
* @var array
*/
protected $attachments = [];
/**
* @var array
*/
protected $recipients = [];
/**
* @var array
*/
protected $bccRecipients = [];
/**
* @var string
*/
protected $subject;
/**
* @var string
*/
protected $from;
/**
* @var string
*/
protected $replyTo;
/**
* Constructor.
*
* @param BasicNotifier $basicNotifier
* @param Swift_Mailer $mail
*/
public function __construct(TwigEnvironment $twig, Swift_Mailer $mailer)
{
$this->mailer = $mailer;
$this->twig = $twig;
}
/**
* @return EmailNotifier
*/
public function setMailer(Swift_Mailer $mailer): self
{
$this->mailer = $mailer;
return $this;
}
public function getMailer(): Swift_Mailer
{
return $this->mailer;
}
/**
* @return EmailNotifier
*/
public function setRecipients(array $recipients): self
{
$this->recipients = $recipients;
return $this;
}
public function getRecipients(): array
{
return $this->recipients;
}
/**
* @return EmailNotifier
*/
public function setBccRecipients(array $bccRecipients): self
{
$this->bccRecipients = $bccRecipients;
return $this;
}
public function getBccRecipients(): array
{
return $this->bccRecipients;
}
/**
* @param string $subject
*
* @return EmailNotifier
*/
public function setSubject(?string $subject): self
{
$this->subject = $subject;
return $this;
}
public function getSubject(): string
{
return $this->subject;
}
/**
* @param mixed $from
*
* @return EmailNotifier
*/
public function setFrom($from): self
{
$this->from = $from;
return $this;
}
/**
* @return mixed
*/
public function getFrom(): ?string
{
return $this->from;
}
/**
* Set the value of "replyTo".
*
* @param string $replyTo
*
* @return EmailNotifier
*/
public function setReplyTo($replyTo): self
{
$this->replyTo = $replyTo;
return $this;
}
/*
* Get the value of "replyTo".
*
* @return string
*/
public function getReplyTo(): ?string
{
return $this->replyTo;
}
/**
* @return EmailNotifier
*/
public function setAttachments(array $attachments): self
{
$this->attachments = $attachments;
return $this;
}
public function getAttachments(): array
{
return $this->attachments;
}
/**
* @return EmailNotifier
*/
public function addRecipient(string $email, bool $isBcc = false): self
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException(sprintf('Invalid email "%s".', $email));
}
if ($isBcc) {
if (!in_array($email, $this->bccRecipients)) {
$this->bccRecipients[] = $email;
}
} else {
if (!in_array($email, $this->recipients)) {
$this->recipients[] = $email;
}
}
return $this;
}
/**
* @return EmailNotifier
*/
public function addRecipients(array $emails, bool $isBcc = false): self
{
foreach ($emails as $email) {
$this->addRecipient($email, $isBcc);
}
return $this;
}
/**
* @return EmailNotifier
*/
public function addRecipientByAccount(Account $account, bool $isBcc = false): self
{
return $this->addRecipient($account->getEmail(), $isBcc);
}
/**
* @param mixed $accounts
*
* @return EmailNotifier
*/
public function addRecipientsByAccounts($accounts, bool $isBcc = false)
{
if (!is_array($accounts)) {
throw new InvalidArgumentException('The "accounts" parameter must be an array or an instance of ObjectCollection');
}
foreach ($accounts as $account) {
$this->addRecipientByAccount($account, $isBcc);
}
return $this;
}
/**
* @return EmailNotifier
*/
public function addAttachment(string $attachment): self
{
if (!in_array($attachment, $this->attachments)) {
$this->attachments[] = $attachment;
}
return $this;
}
/**
* @return EmailNotifier
*/
public function addAttachments(array $attachments): self
{
foreach ($attachments as $attachment) {
$this->addAttachment($attachment);
}
return $this;
}
/**
* @return EmailNotifier
*/
public function init(): self
{
$this
->setSubject(null)
->setRecipients([])
->setBccRecipients([])
->setAttachments([])
;
return $this;
}
/**
* @return EmailNotifier
*/
public function notify(string $template, array $data = [], string $type = 'text/html'): self
{
$message = $this->createMessage(
$this->twig->render(
sprintf('mail/%s.html.twig', $template),
$data
),
$type
);
$this->mailer->send($message);
return $this;
}
protected function createMessage(string $body, string $type = 'text/html'): Swift_Message
{
$message = new Swift_Message();
if ($this->getSubject()) {
$message->setSubject($this->getSubject());
}
if ($this->getFrom()) {
$message->setFrom($this->getFrom());
}
if ($this->getReplyTo()) {
$message->setReplyTo($this->getReplyTo());
}
if (count($this->getRecipients()) > 0) {
$message->setTo($this->getRecipients());
}
if (count($this->getBccRecipients()) > 0) {
$message->setBcc($this->getBccRecipients());
}
foreach ($this->getAttachments() as $attachment) {
if (is_object($attachment) && $attachment instanceof Swift_Attachment) {
$message->attach($attachment);
} elseif (is_string($attachment) && file_exists($attachment) && is_readable($attachment) && !is_dir($attachment)) {
$message->attach(Swift_Attachment::fromPath($attachment));
}
}
$message->setBody($body, $type);
return $message;
}
}

View File

@ -2,8 +2,8 @@
namespace App\Repository\Blog;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use App\Core\Repository\RepositoryQuery;
/**
* class CategoryRepositoryQuery.

View File

@ -4,8 +4,8 @@ namespace App\Repository\Blog;
use App\Entity\Blog\Category;
use App\Entity\User;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
use App\Core\Repository\RepositoryQuery;
/**
* class PostRepositoryQuery.

View File

@ -1,96 +0,0 @@
<?php
namespace App\Repository;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\QueryBuilder;
use Knp\Component\Pager\PaginatorInterface;
/**
* class RepositoryQuery.
*
* @author Simon Vieille <simon@deblan.fr>
*/
abstract class RepositoryQuery
{
protected ServiceEntityRepository $repository;
protected QueryBuilder $query;
protected PaginatorInterface $paginator;
protected string $id;
public function __construct(ServiceEntityRepository $repository, string $id, PaginatorInterface $paginator = null)
{
$this->repository = $repository;
$this->query = $repository->createQueryBuilder($id);
$this->paginator = $paginator;
$this->id = $id;
}
public function __call(string $name, $params): self
{
$fn = function (&$data) {
if (is_string($data)) {
$words = explode(' ', $data);
foreach ($words as $k => $v) {
if (isset($v[0]) && '.' === $v[0]) {
$words[$k] = $this->id.$v;
}
}
$data = implode(' ', $words);
} elseif (is_array($data)) {
foreach ($data as $k => $v) {
$fn($data[$k]);
}
}
return $data;
};
foreach ($params as $key => $value) {
$fn($params[$key]);
}
call_user_func_array([$this->query, $name], $params);
return $this;
}
public function create()
{
$class = get_called_class();
return new $class($this->repository, $this->paginator);
}
public function call(callable $fn): self
{
$fn($this->query, $this);
return $this;
}
public function findOne()
{
return $this->query->getQuery()
->setMaxResults(1)
->getOneOrNullResult()
;
}
public function find()
{
return $this->query->getQuery()->getResult();
}
public function paginate(int $page = 1, int $limit = 20)
{
return $this->paginator->paginate($this->query->getQuery(), $page, $limit);
}
public function getRepository(): ServiceEntityRepository
{
return $this->repository;
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Repository\Site;
use App\Entity\Site\Menu;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class MenuRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Menu::class);
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Repository\Site;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
/**
* class MenuRepositoryQuery.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class MenuRepositoryQuery extends RepositoryQuery
{
public function __construct(MenuRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'm', $paginator);
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Repository\Site;
use App\Entity\Site\Navigation;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class NavigationRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Navigation::class);
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Repository\Site;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
/**
* class NavigationRepositoryQuery.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationRepositoryQuery extends RepositoryQuery
{
public function __construct(NavigationRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'n', $paginator);
}
}

View File

@ -1,38 +0,0 @@
<?php
namespace App\Repository\Site;
use App\Entity\Site\Node;
use Doctrine\ORM\EntityManagerInterface;
use Gedmo\Tree\Entity\Repository\NestedTreeRepository;
class NodeRepository extends NestedTreeRepository
{
public function __construct(EntityManagerInterface $manager)
{
parent::__construct($manager, $manager->getClassMetadata(Node::class));
}
public function urlExists($url, Node $node)
{
$query = $this->createQueryBuilder('n')
->join('n.menu', 'm')
->where('n.url = :url')
->andWhere('m.navigation = :navigation')
->setParameter(':url', $url)
->setParameter(':navigation', $node->getMenu()->getNavigation())
;
if ($node->getId()) {
$query
->andWhere('n.id != :id')
->setParameter(':id', $node->getId())
;
}
return $query->getQuery()
->setMaxResults(1)
->getOneOrNullResult()
;
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Repository\Site\Page;
use App\Entity\Site\Page\Block;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class BlockRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Block::class);
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace App\Repository\Site\Page;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
/**
* class BlockRepositoryQuery.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class BlockRepositoryQuery extends RepositoryQuery
{
public function __construct(BlockRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'b', $paginator);
}
}

View File

@ -1,15 +0,0 @@
<?php
namespace App\Repository\Site\Page;
use App\Entity\Site\Page\Page;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class PageRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Page::class);
}
}

View File

@ -1,29 +0,0 @@
<?php
namespace App\Repository\Site\Page;
use App\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
/**
* class PageRepositoryQuery.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageRepositoryQuery extends RepositoryQuery
{
public function __construct(PageRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'p', $paginator);
}
public function filterById($id)
{
$this
->where('.id = :id')
->setParameter(':id', $id)
;
return $this;
}
}

View File

@ -3,6 +3,7 @@
namespace App\Repository;
use Knp\Component\Pager\PaginatorInterface;
use App\Core\Repository\RepositoryQuery;
/**
* class UserRepositoryQuery.

View File

@ -1,69 +0,0 @@
<?php
namespace App\Router;
use App\Controller\Site\PageController;
use App\Repository\Site\NavigationRepositoryQuery;
use Symfony\Component\Config\Loader\Loader;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
/**
* class SiteRouteLoader.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class SiteRouteLoader extends Loader
{
protected NavigationRepositoryQuery $navigationQuery;
protected $isLoaded = false;
public function __construct(NavigationRepositoryQuery $navigationQuery)
{
$this->navigationQuery = $navigationQuery;
}
public function load($resource, ?string $type = null)
{
if (true === $this->isLoaded) {
throw new \RuntimeException('Do not add the "extra" loader twice');
}
$routes = new RouteCollection();
$navigations = $this->navigationQuery->find();
foreach ($navigations as $navigation) {
foreach ($navigation->getMenus() as $menu) {
foreach ($menu->getRootNode()->getAllChildren() as $node) {
if ($node->getParent() === null) {
continue;
}
$requirements = [];
$defaults = [
'_controller' => PageController::class.'::show',
'_node' => $node->getId(),
'_menu' => $menu->getId(),
'_page' => $node->getPage() ? $node->getPage()->getId() : null,
'_navigation' => $navigation->getId(),
];
$route = new Route($node->getUrl(), $defaults, $requirements);
$route->setHost($navigation->getDomain());
$routes->add($node->getRouteName(), $route);
}
}
}
$this->isLoaded = true;
return $routes;
}
public function supports($resource, string $type = null)
{
return 'extra' === $type;
}
}

View File

@ -1,13 +0,0 @@
<?php
namespace App\Security;
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
class TokenGenerator implements TokenGeneratorInterface
{
public function generateToken(): string
{
return rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
}
}

View File

@ -1,51 +0,0 @@
<?php
namespace App\Site;
/**
* class PageConfiguration.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageConfiguration
{
protected string $className;
protected string $name;
protected array $templates;
public function setClassName(string $className): self
{
$this->className = $className;
return $this;
}
public function getClassName(): string
{
return $this->className;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function setTemplates(array $templates): self
{
$this->templates = $templates;
return $this;
}
public function getTemplates(): array
{
return $this->templates;
}
}

View File

@ -1,48 +0,0 @@
<?php
namespace App\Site;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* class PageLocator.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageLocator
{
protected array $params;
protected array $pages;
public function __construct(ParameterBagInterface $bag)
{
$this->params = $bag->get('app');
$this->loadPages();
}
public function getPages(): array
{
return $this->pages;
}
public function getPage($className)
{
return $this->pages[$className] ?? null;
}
protected function loadPages(): void
{
$params = $this->params['site']['pages'] ?? [];
foreach ($params as $className => $conf) {
$pageConfiguration = new PageConfiguration();
$pageConfiguration
->setClassName($className)
->setName($conf['name'])
->setTemplates($conf['templates'])
;
$this->pages[$className] = $pageConfiguration;
}
}
}

View File

@ -1,69 +0,0 @@
<?php
namespace App\Site;
use App\Entity\Site\Menu;
use App\Entity\Site\Navigation;
use App\Entity\Site\Node;
use App\Entity\Site\Page\Page;
use App\Repository\Site\NavigationRepositoryQuery;
use App\Repository\Site\NodeRepository;
use App\Repository\Site\Page\PageRepositoryQuery;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* class SiteRequest.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class SiteRequest
{
protected RequestStack $requestStack;
protected NodeRepository $nodeRepository;
protected NavigationRepositoryQuery $navigationRepositoryQuery;
protected PageRepositoryQuery $pageRepositoryQuery;
public function __construct(RequestStack $requestStack, NodeRepository $nodeRepository)
{
$this->requestStack = $requestStack;
$this->nodeRepository = $nodeRepository;
}
public function getNode(): ?Node
{
$request = $this->requestStack->getCurrentRequest();
if ($request->attributes->has('_node')) {
return $this->nodeRepository->findOneBy([
'id' => $request->attributes->get('_node'),
]);
}
return null;
}
public function getPage(): ?Page
{
$node = $this->getNode();
if ($node && $node->getPage()) {
return $node->getPage();
}
return null;
}
public function getMenu(): ?Menu
{
$node = $this->getNode();
return null !== $node ? $node->getMenu() : null;
}
public function getNavigation(): ?Navigation
{
$menu = $this->getMenu();
return null !== $menu ? $menu->getNavigation() : null;
}
}

View File

@ -1,26 +0,0 @@
<?php
namespace App\Slugify;
use Cocur\Slugify\Slugify as BaseSlugify;
/**
* class CodeSlugify.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class CodeSlugify extends Slugify
{
protected function create(): BaseSlugify
{
$slugify = new BaseSlugify([
'separator' => '_',
'lowercase' => true,
]);
$slugify->activateRuleSet('french');
$slugify->addRule("'", '');
return $slugify;
}
}

View File

@ -1,31 +0,0 @@
<?php
namespace App\Slugify;
use Cocur\Slugify\Slugify as BaseSlugify;
/**
* class Slugify.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class Slugify
{
public function slugify($data)
{
return $this->create()->slugify($data);
}
protected function create(): BaseSlugify
{
$slugify = new BaseSlugify([
'separator' => '-',
'lowercase' => true,
]);
$slugify->activateRuleSet('french');
$slugify->addRule("'", '');
return $slugify;
}
}

View File

@ -48,37 +48,5 @@
</li>
</ul>
</div>
<div class="col-12">
<table class="table">
<thead class="thead-light">
<tr>
<th>Derniers articles</th>
</tr>
</thead>
<tbody>
{% for item in posts %}
<tr>
<td>
<a href="{{ path('admin_blog_post_show', {entity: item.id}) }}" class="text-body">
{{ item.title }}
</a>
</td>
</tr>
{% else %}
<tr>
<td class="text-center p-4 text-black-50">
<div class="display-1">
<span class="fa fa-search"></span>
</div>
<div class="display-5 mt-3">
Aucun résultat
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}