@@ -0,0 +1,106 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Authenticator; | |||
use Lc\AdminBundle\IModel\User\UserInterface; | |||
use Lc\AdminBundle\Manager\EntityManager; | |||
use Symfony\Component\HttpFoundation\RedirectResponse; | |||
use Symfony\Component\HttpFoundation\Request; | |||
use Symfony\Component\Security\Core\User\UserInterface as SfUserInterface; | |||
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\UserProviderInterface; | |||
use Symfony\Component\Security\Csrf\CsrfToken; | |||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; | |||
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator; | |||
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface; | |||
use Symfony\Component\Security\Http\Util\TargetPathTrait; | |||
class LoginFormAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface | |||
{ | |||
use TargetPathTrait; | |||
public const LOGIN_ROUTE = 'login'; | |||
private $entityManager; | |||
private $urlGenerator; | |||
private $csrfTokenManager; | |||
private $passwordEncoder; | |||
public function __construct(EntityManager $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 self::LOGIN_ROUTE === $request->attributes->get('_route') | |||
&& $request->isMethod('POST'); | |||
} | |||
public function getCredentials(Request $request) | |||
{ | |||
$credentials = [ | |||
'email' => $request->request->get('email'), | |||
'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(UserInterface::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, SfUserInterface $user) | |||
{ | |||
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']); | |||
} | |||
/** | |||
* Used to upgrade (rehash) the user's password automatically over time. | |||
*/ | |||
public function getPassword($credentials): ?string | |||
{ | |||
return $credentials['password']; | |||
} | |||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey) | |||
{ | |||
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) { | |||
return new RedirectResponse($targetPath); | |||
} | |||
return new RedirectResponse($this->urlGenerator->generate('lc_admin_dashboard')); | |||
} | |||
protected function getLoginUrl() | |||
{ | |||
return $this->urlGenerator->generate(self::LOGIN_ROUTE); | |||
} | |||
} |
@@ -0,0 +1,125 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Command; | |||
use Lc\AdminBundle\IModel\User\UserInterface; | |||
use Lc\AdminBundle\Manager\EntityManager; | |||
use Symfony\Component\Console\Command\Command; | |||
use Symfony\Component\Console\Input\InputArgument; | |||
use Symfony\Component\Console\Input\InputInterface; | |||
use Symfony\Component\Console\Output\OutputInterface; | |||
use Symfony\Component\Console\Question\Question; | |||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; | |||
class CreateUserCommand extends Command | |||
{ | |||
private $passwordEncoder; | |||
private $em; | |||
public function __construct(UserPasswordEncoderInterface $passwordEncoder, EntityManager $entityManager) | |||
{ | |||
parent::__construct(); | |||
$this->passwordEncoder = $passwordEncoder; | |||
$this->em = $entityManager; | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
protected function configure() | |||
{ | |||
$this | |||
->setName('user:create') | |||
->setDescription('Create a user.') | |||
->setDefinition(array( | |||
new InputArgument('email', InputArgument::REQUIRED, 'The email'), | |||
new InputArgument('password', InputArgument::REQUIRED, 'The password'), | |||
new InputArgument('role', InputArgument::REQUIRED, 'ROLE'), | |||
)) | |||
->setHelp(''); | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
protected function execute(InputInterface $input, OutputInterface $output) | |||
{ | |||
$email = $input->getArgument('email'); | |||
$password = $input->getArgument('password'); | |||
$role = $input->getArgument('role'); | |||
$user = $this->em->new(UserInterface::class); | |||
$user->setEmail($email); | |||
$user->setRoles(array($role)); | |||
$password = $this->passwordEncoder->encodePassword($user, $password); | |||
$user->setPassword($password); | |||
$this->em->create($user); | |||
$this->em->flush(); | |||
$output->writeln(sprintf('Created user <comment>%s</comment>', $email)); | |||
return Command::SUCCESS; | |||
} | |||
/** | |||
* {@inheritdoc} | |||
*/ | |||
protected function interact(InputInterface $input, OutputInterface $output) | |||
{ | |||
$questions = array(); | |||
if (!$input->getArgument('email')) { | |||
$question = new Question('Email : '); | |||
$question->setValidator(function ($password) { | |||
if (empty($password)) { | |||
throw new \Exception('Email can not be empty'); | |||
} | |||
return $password; | |||
}); | |||
$questions['email'] = $question; | |||
} | |||
if (!$input->getArgument('password')) { | |||
$question = new Question('Password : '); | |||
$question->setValidator(function ($password) { | |||
if (empty($password)) { | |||
throw new \Exception('Password can not be empty'); | |||
} | |||
return $password; | |||
}); | |||
$question->setHidden(true); | |||
$questions['password'] = $question; | |||
} | |||
if (!$input->getArgument('role')) { | |||
$question = new Question('Rôle [admin/superadmin/user] : '); | |||
$question->setValidator(function ($role) { | |||
if ($role == 'admin') { | |||
$role = 'ROLE_ADMIN'; | |||
} else if ($role == 'superadmin') { | |||
$role = 'ROLE_SUPER_ADMIN'; | |||
} else if ($role == 'user') { | |||
$role = 'ROLE_USER'; | |||
} else { | |||
throw new \Exception('Choose a role'); | |||
} | |||
return $role; | |||
}); | |||
$questions['role'] = $question; | |||
} | |||
foreach ($questions as $name => $question) { | |||
$answer = $this->getHelper('question')->ask($input, $output, $question); | |||
$input->setArgument($name, $answer); | |||
} | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Controller\Admin; | |||
use App\Entity\Page; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController as EaAbstractCrudController; | |||
abstract class AbstractCrudController extends EaAbstractCrudController | |||
{ | |||
/* | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return [ | |||
IdField::new('id'), | |||
TextField::new('title'), | |||
TextEditorField::new('description'), | |||
]; | |||
} | |||
*/ | |||
} |
@@ -0,0 +1,60 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Controller\Admin; | |||
use App\Entity\Page; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; | |||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
class DashboardController extends AbstractDashboardController | |||
{ | |||
public function index(): Response | |||
{ | |||
return parent::index(); | |||
} | |||
public function configureDashboard(): Dashboard | |||
{ | |||
return Dashboard::new() | |||
// the name visible to end users | |||
->setTitle('LA CLIC !') | |||
// you can include HTML contents too (e.g. to link to an image) | |||
->setTitle('<img src="assets/img/laclic.png" width="100px">') | |||
// the path defined in this method is passed to the Twig asset() function | |||
->setFaviconPath('favicon.svg') | |||
// the domain used by default is 'messages' | |||
->setTranslationDomain('lcadmin'); | |||
} | |||
public function configureCrud(): Crud | |||
{ | |||
$crud = Crud::new(); | |||
return $crud | |||
->addFormTheme('@FOSCKEditor/Form/ckeditor_widget.html.twig'); | |||
} | |||
public function configureMenuItems(): iterable | |||
{ | |||
return [ | |||
MenuItem::linkToDashboard('Tableau de bord', 'fa fa-home'), | |||
MenuItem::linkToCrud('Pages', 'fa fa-tags', Page::class), | |||
/* | |||
MenuItem::section('Blog'), | |||
MenuItem::linkToCrud('Categories', 'fa fa-tags', Category::class), | |||
MenuItem::linkToCrud('Blog Posts', 'fa fa-file-text', BlogPost::class), | |||
MenuItem::section('Users'), | |||
MenuItem::linkToCrud('Comments', 'fa fa-comment', Comment::class), | |||
MenuItem::linkToCrud('Users', 'fa fa-user', User::class),*/ | |||
//MenuItem::linkToLogout('Déconnexion', 'fa fa-exit'), | |||
]; | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
<?php | |||
namespace App\Controller\Admin; | |||
use App\Entity\Page; | |||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField; | |||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField; | |||
class PageCrudController extends AbstractCrudController | |||
{ | |||
public static function getEntityFqcn(): string | |||
{ | |||
return Page::class; | |||
} | |||
public function configureFields(string $pageName): iterable | |||
{ | |||
return [ | |||
TextField::new('title'), | |||
TextEditorField::new('description'), | |||
ImageField::new('image') | |||
->setBasePath('/uploads/') | |||
->setUploadDir('public/uploads/'), | |||
TextField::new('devAlias'), | |||
ChoiceField::new('status') | |||
->setChoices(['En ligne'=> 1, 'Hors ligne'=>0]) | |||
->setFormTypeOption('expanded', true) | |||
->setFormTypeOption('multiple', false) | |||
->setCustomOption('widget', false) | |||
]; | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Controller\Admin; | |||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
use Symfony\Component\HttpFoundation\Response; | |||
use Symfony\Component\Routing\Annotation\Route; | |||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; | |||
class SecurityController extends AbstractController | |||
{ | |||
public function login(AuthenticationUtils $authenticationUtils): Response | |||
{ | |||
if ($this->getUser()) { | |||
return $this->redirectToRoute('lc_'); | |||
} | |||
// get the login error if there is one | |||
$error = $authenticationUtils->getLastAuthenticationError(); | |||
// last username entered by the user | |||
$lastUsername = $authenticationUtils->getLastUsername(); | |||
return $this->render('@EasyAdmin/page/login.html.twig', [ | |||
// parameters usually defined in Symfony login forms | |||
'error' => $error, | |||
'last_username' => $lastUsername, | |||
// OPTIONAL parameters to customize the login form: | |||
// the translation_domain to use (define this option only if you are | |||
// rendering the login template in a regular Symfony controller; when | |||
// rendering it from an EasyAdmin Dashboard this is automatically set to | |||
// the same domain as the rest of the Dashboard) | |||
'translation_domain' => 'admin', | |||
// the title visible above the login form (define this option only if you are | |||
// rendering the login template in a regular Symfony controller; when rendering | |||
// it from an EasyAdmin Dashboard this is automatically set as the Dashboard title) | |||
'page_title' => '<img src="assets/img/laclic.png" >', | |||
// the string used to generate the CSRF token. If you don't define | |||
// this parameter, the login form won't include a CSRF token | |||
'csrf_token_intention' => 'authenticate', | |||
// the URL users are redirected to after the login (default: '/admin') | |||
'target_path' => $this->generateUrl('lc_admin_dashboard'), | |||
// the label displayed for the username form field (the |trans filter is applied to it) | |||
'username_label' => 'Your username', | |||
// the label displayed for the password form field (the |trans filter is applied to it) | |||
'password_label' => 'Your password', | |||
// the label displayed for the Sign In form button (the |trans filter is applied to it) | |||
'sign_in_label' => 'Log in', | |||
// the 'name' HTML attribute of the <input> used for the username field (default: '_username') | |||
'username_parameter' => 'email', | |||
// the 'name' HTML attribute of the <input> used for the password field (default: '_password') | |||
'password_parameter' => 'password', | |||
]); | |||
} | |||
public function logout() | |||
{ | |||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.'); | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
<?php | |||
namespace Lc\AdminBundle\DependencyInjection; | |||
use Symfony\Component\Config\FileLocator; | |||
use Symfony\Component\DependencyInjection\ContainerBuilder; | |||
use Symfony\Component\DependencyInjection\Extension\Extension; | |||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; | |||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | |||
class LcAdminExtension extends Extension implements PrependExtensionInterface | |||
{ | |||
public function load(array $configs, ContainerBuilder $container) | |||
{ | |||
} | |||
public function prepend(ContainerBuilder $container) | |||
{ | |||
/*$loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/easy_admin')); | |||
$loader->load('base.yaml'); | |||
$loader->load('entities/merchant.yaml');*/ | |||
} | |||
} |
@@ -0,0 +1,30 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Event\EntityManager; | |||
use Lc\AdminBundle\IModel\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'; | |||
protected EntityInterface $entity; | |||
public function __construct(EntityInterface $entity) | |||
{ | |||
$this->entity = $entity; | |||
} | |||
public function getEntity(): EntityInterface | |||
{ | |||
return $this->entity; | |||
} | |||
} |
@@ -0,0 +1,9 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface BlameableInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface DevAliasInterface | |||
{ | |||
} |
@@ -0,0 +1,11 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface ImageInterface | |||
{ | |||
} |
@@ -0,0 +1,10 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface SeoInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface SluggableInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface SortableInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface StatusInterface | |||
{ | |||
} |
@@ -0,0 +1,9 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface TimestampableInterface | |||
{ | |||
} |
@@ -0,0 +1,22 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\Cms; | |||
interface TreeInterface | |||
{ | |||
/** | |||
* Retourne le parent d'une entité | |||
* | |||
* @return entity | |||
*/ | |||
public function getParent(); | |||
/** | |||
* Retourne les enfants d'une entité | |||
* | |||
* @return entity | |||
*/ | |||
public function getChildrens(); | |||
} |
@@ -0,0 +1,7 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel; | |||
interface EntityInterface | |||
{ | |||
} |
@@ -0,0 +1,8 @@ | |||
<?php | |||
namespace Lc\AdminBundle\IModel\User; | |||
interface UserInterface | |||
{ | |||
} |
@@ -0,0 +1,15 @@ | |||
<?php | |||
namespace Lc\AdminBundle; | |||
use Lc\AdminBundle\DependencyInjection\LcAdminExtension; | |||
use Symfony\Component\HttpKernel\Bundle\Bundle; | |||
class LcAdminBundle extends Bundle | |||
{ | |||
public function getContainerExtension() | |||
{ | |||
return new LcAdminExtension(); | |||
} | |||
} |
@@ -0,0 +1,90 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Manager; | |||
use Doctrine\ORM\EntityManager as DoctrineEntityManager; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Lc\AdminBundle\Event\EntityManager\EntityManagerEvent; | |||
use Lc\AdminBundle\IModel\EntityInterface; | |||
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 getRepository($className) | |||
{ | |||
return $this->entityManager->getRepository($this->getEntityName($className)); | |||
} | |||
public function new($className) | |||
{ | |||
return new $this->getEntityName($className); | |||
} | |||
public function create(EntityInterface $entity): self | |||
{ | |||
$this->persist($entity); | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT); | |||
return $this; | |||
} | |||
public function update(EntityInterface $entity): self | |||
{ | |||
$this->persist($entity); | |||
$this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT); | |||
return $this; | |||
} | |||
public function delete(EntityInterface $entity): self | |||
{ | |||
$this->remove($entity); | |||
$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; | |||
} | |||
protected function persist(EntityInterface $entity) | |||
{ | |||
$this->entityManager->persist($entity); | |||
} | |||
public function getEntityName($className) | |||
{ | |||
if (substr($className, -9) === 'Interface') { | |||
return $this->entityManager->getClassMetadata($className)->getName(); | |||
}else{ | |||
return $className; | |||
} | |||
} | |||
} |
@@ -0,0 +1,66 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Lc\AdminBundle\IModel\Cms\BlameableInterface; | |||
use Lc\AdminBundle\IModel\Cms\DevAliasInterface; | |||
use Lc\AdminBundle\IModel\Cms\SeoInterface; | |||
use Lc\AdminBundle\IModel\Cms\SluggableInterface; | |||
use Lc\AdminBundle\IModel\Cms\SortableInterface; | |||
use Lc\AdminBundle\IModel\Cms\TimestampableInterface; | |||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Lc\AdminBundle\IModel\EntityInterface; | |||
/** | |||
* @ORM\MappedSuperclass | |||
*/ | |||
abstract class AbstractDocument implements BlameableInterface, SeoInterface, SluggableInterface, SortableInterface, StatusInterface, TimestampableInterface, DevAliasInterface, EntityInterface | |||
{ | |||
use BlameableTrait; | |||
use SeoTrait; | |||
use SluggableTrait; | |||
use SortableTrait; | |||
use StatusTrait; | |||
use TimestampableTrait; | |||
use DevAliasTrait; | |||
/** | |||
* @ORM\Column(type="string", length=255) | |||
*/ | |||
protected $title; | |||
/** | |||
* @ORM\Column(type="text", nullable=true) | |||
*/ | |||
protected $description; | |||
public function getTitle(): ?string | |||
{ | |||
return $this->title; | |||
} | |||
public function setTitle(string $title): self | |||
{ | |||
$this->title = $title; | |||
return $this; | |||
} | |||
public function getDescription(): ?string | |||
{ | |||
return $this->description; | |||
} | |||
public function setDescription(?string $description): self | |||
{ | |||
$this->description = $description; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use App\IModel\UserInterface; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
trait BlameableTrait | |||
{ | |||
/** | |||
* @Gedmo\Blameable(on="create") | |||
* @ORM\ManyToOne(targetEntity="App\Entity\User") | |||
* @ORM\JoinColumn(nullable=false) | |||
*/ | |||
protected $createdBy; | |||
/** | |||
* @Gedmo\Blameable(on="update") | |||
* @ORM\ManyToOne(targetEntity="App\Entity\User") | |||
* @ORM\JoinColumn(nullable=false) | |||
*/ | |||
protected $updatedBy; | |||
public function getCreatedBy(): ?UserInterface | |||
{ | |||
return $this->createdBy; | |||
} | |||
public function setCreatedBy(?UserInterface $createdBy): self | |||
{ | |||
$this->createdBy = $createdBy; | |||
return $this; | |||
} | |||
public function getUpdatedBy(): ?UserInterface | |||
{ | |||
return $this->updatedBy; | |||
} | |||
public function setUpdatedBy(?UserInterface $updatedBy): self | |||
{ | |||
$this->updatedBy = $updatedBy; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\Common\Collections\ArrayCollection; | |||
use Doctrine\ORM\Mapping as ORM; | |||
trait DevAliasTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $devAlias; | |||
public function getDevAlias(): ?string | |||
{ | |||
return $this->devAlias; | |||
} | |||
public function setDevAlias(?string $devAlias): self | |||
{ | |||
$this->devAlias = $devAlias; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,52 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Symfony\Component\HttpFoundation\File\File; | |||
trait ImageTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $image; | |||
/* /** | |||
* @Vich\UploadableField(mapping="images", fileNameProperty="image") | |||
* @var File | |||
*/ | |||
//protected $imageFile;*/ | |||
/* | |||
public function setImageFile(File $image = null) | |||
{ | |||
$this->imageFile = $image; | |||
// VERY IMPORTANT: | |||
// It is required that at least one field changes if you are using Doctrine, | |||
// otherwise the event listeners won't be called and the file is lost | |||
if ($image) { | |||
// if 'updatedAt' is not defined in your entity, use another property | |||
$this->updatedAt = new \DateTime('now'); | |||
} | |||
} | |||
public function getImageFile() | |||
{ | |||
return $this->imageFile; | |||
}*/ | |||
public function getImage(): ?string | |||
{ | |||
return $this->image; | |||
} | |||
public function setImage(?string $image): self | |||
{ | |||
$this->image = $image; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
trait SeoTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $metaTitle; | |||
/** | |||
* @ORM\Column(type="text", nullable=true) | |||
*/ | |||
protected $metaDescription; | |||
/** | |||
* @var array | |||
* @ORM\Column(type="array", nullable=true) | |||
*/ | |||
protected $oldUrls; | |||
public function getMetaTitle(): ?string | |||
{ | |||
return $this->metaTitle; | |||
} | |||
public function setMetaTitle(?string $metaTitle): self | |||
{ | |||
$this->metaTitle = $metaTitle; | |||
return $this; | |||
} | |||
public function getMetaDescription(): ?string | |||
{ | |||
return $this->metaDescription; | |||
} | |||
public function setMetaDescription(?string $metaDescription): self | |||
{ | |||
$this->metaDescription = $metaDescription; | |||
return $this; | |||
} | |||
public function setOldUrls($oldUrls): self | |||
{ | |||
$this->oldUrls = $oldUrls; | |||
return $this; | |||
} | |||
public function getOldUrls(): ?array | |||
{ | |||
return $this->oldUrls; | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
trait SluggableTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=255) | |||
* @Gedmo\Slug(fields={"title"}) | |||
*/ | |||
protected $slug; | |||
public function getSlug(): ?string | |||
{ | |||
return $this->slug; | |||
} | |||
public function setSlug(?string $slug): self | |||
{ | |||
$this->slug = $slug; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
trait SortableTrait | |||
{ | |||
/** | |||
* @var string | |||
* @ORM\Column(type="float") | |||
*/ | |||
protected $position = 0; | |||
/** | |||
* @return float | |||
*/ | |||
public function getPosition(): float | |||
{ | |||
return $this->position; | |||
} | |||
/** | |||
* @param float $position | |||
* @return $this | |||
*/ | |||
public function setPosition(float $position): self | |||
{ | |||
$this->position = $position; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
trait StatusTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="float") | |||
*/ | |||
protected $status; | |||
public function getStatus(): ?float | |||
{ | |||
return $this->status; | |||
} | |||
public function setStatus(float $status): self | |||
{ | |||
$this->status = $status; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,46 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Gedmo\Mapping\Annotation as Gedmo; | |||
trait TimestampableTrait | |||
{ | |||
/** | |||
* @ORM\Column(type="datetime") | |||
* @Gedmo\Timestampable(on="create") | |||
*/ | |||
protected $createdAt; | |||
/** | |||
* @ORM\Column(type="datetime") | |||
* @Gedmo\Timestampable(on="update") | |||
*/ | |||
protected $updatedAt; | |||
public function getCreatedAt(): ?\DateTimeInterface | |||
{ | |||
return $this->createdAt; | |||
} | |||
public function setCreatedAt(\DateTimeInterface $createdAt): self | |||
{ | |||
$this->createdAt = $createdAt; | |||
return $this; | |||
} | |||
public function getUpdatedAt(): ?\DateTimeInterface | |||
{ | |||
return $this->updatedAt; | |||
} | |||
public function setUpdatedAt(\DateTimeInterface $updatedAt): self | |||
{ | |||
$this->updatedAt = $updatedAt; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,11 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\Cms; | |||
use Doctrine\Common\Collections\ArrayCollection; | |||
use Doctrine\ORM\Mapping as ORM; | |||
trait TreeTrait | |||
{ | |||
} |
@@ -0,0 +1,155 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Model\User; | |||
use Doctrine\ORM\Mapping as ORM; | |||
use Lc\AdminBundle\IModel\EntityInterface; | |||
use Symfony\Component\Security\Core\User\UserInterface; | |||
/** | |||
* @ORM\MappedSuperclass() | |||
*/ | |||
abstract class User implements EntityInterface, UserInterface | |||
{ | |||
/** | |||
* @ORM\Column(type="string", length=180, unique=true) | |||
*/ | |||
protected $email; | |||
/** | |||
* @ORM\Column(type="json") | |||
*/ | |||
protected $roles = []; | |||
/** | |||
* @var string The hashed password | |||
* @ORM\Column(type="string") | |||
*/ | |||
protected $password; | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $lastname; | |||
/** | |||
* @ORM\Column(type="string", length=255, nullable=true) | |||
*/ | |||
protected $firstname; | |||
/** | |||
* @ORM\Column(type="boolean") | |||
*/ | |||
protected $isVerified = false; | |||
public function getEmail(): ?string | |||
{ | |||
return $this->email; | |||
} | |||
public function setEmail(string $email): self | |||
{ | |||
$this->email = $email; | |||
return $this; | |||
} | |||
/** | |||
* A visual identifier that represents this user. | |||
* | |||
* @see UserInterface | |||
*/ | |||
public function getUsername(): string | |||
{ | |||
return (string)$this->email; | |||
} | |||
/** | |||
* @see UserInterface | |||
*/ | |||
public function getRoles(): array | |||
{ | |||
$roles = $this->roles; | |||
// guarantee every user at least has ROLE_USER | |||
$roles[] = 'ROLE_USER'; | |||
return array_unique($roles); | |||
} | |||
public function setRoles(array $roles): self | |||
{ | |||
$this->roles = $roles; | |||
return $this; | |||
} | |||
/** | |||
* @see UserInterface | |||
*/ | |||
public function getPassword(): string | |||
{ | |||
return (string)$this->password; | |||
} | |||
public function setPassword(string $password): self | |||
{ | |||
$this->password = $password; | |||
return $this; | |||
} | |||
/** | |||
* @see UserIn | |||
*/ | |||
public function getSalt() | |||
{ | |||
// not needed when using the "bcrypt" algorithm in security.yaml | |||
} | |||
/** | |||
* @see UserInterface | |||
*/ | |||
public function eraseCredentials() | |||
{ | |||
// If you store any temporary, sensitive data on the user, clear it here | |||
// $this->plainPassword = null; | |||
} | |||
public function getLastname(): ?string | |||
{ | |||
return $this->lastname; | |||
} | |||
public function setLastname(?string $lastname): self | |||
{ | |||
$this->lastname = $lastname; | |||
return $this; | |||
} | |||
public function getFirstname(): ?string | |||
{ | |||
return $this->firstname; | |||
} | |||
public function setFirstname(?string $firstname): self | |||
{ | |||
$this->firstname = $firstname; | |||
return $this; | |||
} | |||
public function isVerified(): bool | |||
{ | |||
return $this->isVerified; | |||
} | |||
public function setIsVerified(bool $isVerified): self | |||
{ | |||
$this->isVerified = $isVerified; | |||
return $this; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
#Laclic LcAdminBundle | |||
Administration basé sur EasyAdmin 3. Développé par <a href="https://www.laclic.fr">la Clic!</a> | |||
Require : | |||
- Symfony > 5.3 | |||
- EasyAdmin > 5.3 | |||
- FOS/Ckeditor-bundle: "^2.2", | |||
@@ -0,0 +1,114 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Repository; | |||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface; | |||
use Doctrine\ORM\EntityManagerInterface; | |||
use Doctrine\ORM\EntityRepository; | |||
use Doctrine\ORM\QueryBuilder; | |||
use Lc\AdminBundle\IModel\Cms\StatusInterface; | |||
abstract class BaseRepository extends EntityRepository implements ServiceEntityRepositoryInterface, BaseRepositoryInterface | |||
{ | |||
protected $merchantUtils; | |||
protected $utils; | |||
public function __construct(EntityManagerInterface $entityManager) | |||
{ | |||
parent::__construct($entityManager, $entityManager->getClassMetadata($this->getInterfaceClass())); | |||
} | |||
public function findByTerm($field, $term, $limit=10){ | |||
$qb = $this->findByMerchantQuery(); | |||
if($this->utils->hasFilterAssociation($field, '_')){ | |||
$aliasRelation = $this->utils->getFilterAssociationAlias($field, '_'); | |||
$qb->innerJoin('e.'.$aliasRelation, $aliasRelation); | |||
$qb->select($this->utils->getFilterPropertyInit($field)); | |||
$qb->groupBy($this->utils->getFilterPropertyInit($field)); | |||
$qb->andWhere( | |||
$qb->expr()->like($this->utils->getFilterPropertyInit($field), ':term')); | |||
}else { | |||
$qb->select('e.' . $field); | |||
$qb->groupBy('e.' . $field); | |||
$qb->andWhere( | |||
$qb->expr()->like('e.' . $field, ':term')); | |||
} | |||
$qb->setParameter('term', '%'.$term.'%'); | |||
$qb->setMaxResults($limit); | |||
return $qb->getQuery()->getResult(); | |||
} | |||
public function findOneByOldUrl($url) | |||
{ | |||
$qb = $this->createQueryBuilder('entity') | |||
->where('entity.oldUrls LIKE :oldUrl') | |||
->andWhere('entity.status = 1') | |||
->setParameter(':oldUrl', '%'.$url.'%'); | |||
return $qb->getQuery()->getOneOrNullResult(); | |||
} | |||
public function findByMerchantQuery() :QueryBuilder | |||
{ | |||
return $this->createQueryBuilder('e') | |||
->where('e.merchant = :currentMerchant') | |||
->setParameter('currentMerchant', $this->merchantUtils->getMerchantCurrent()->getId()) ; | |||
} | |||
public function findAll() | |||
{ | |||
return $this->findBy(array()); | |||
} | |||
public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||
{ | |||
$className = $this->getClassMetadata()->getName(); | |||
$entity = new $className; | |||
if($entity instanceof StatusInterface){ | |||
if (!isset($criteria['status'])) $criteria['status'] = 1; | |||
if ($criteria['status'] === false) unset($criteria['status']); | |||
} | |||
return parent::findBy($criteria, $orderBy, $limit, $offset); | |||
} | |||
public function findOneBy(array $criteria, array $orderBy = null) | |||
{ | |||
$className = $this->getClassMetadata()->getName(); | |||
$entity = new $className; | |||
if($entity instanceof StatusInterface){ | |||
if (!isset($criteria['status'])) $criteria['status'] = 1; | |||
if ($criteria['status'] === false) unset($criteria['status']); | |||
} | |||
return parent::findOneBy($criteria, $orderBy); | |||
} | |||
public function findSimilarSlug($merchant){ | |||
$qb = $this->createQueryBuilder('entity') | |||
->select('entity.id, COUNT(entity.slug) as niche') | |||
->andWhere('entity.status>=0') | |||
->andWhere('entity.merchant= :merchant') | |||
->setParameter('merchant', $merchant) | |||
->groupBy('entity.slug') | |||
->having('COUNT(entity.slug) >1'); | |||
return $qb->getQuery()->getResult(); | |||
} | |||
} |
@@ -0,0 +1,15 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Repository; | |||
interface BaseRepositoryInterface | |||
{ | |||
/** | |||
* Retourne la class ou l'interface correspondant à ce repository | |||
* | |||
* @return string | |||
*/ | |||
public function getInterfaceClass(); | |||
} |
@@ -0,0 +1,68 @@ | |||
<?php | |||
namespace Lc\AdminBundle\Repository\User; | |||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | |||
use Doctrine\Persistence\ManagerRegistry; | |||
use Lc\AdminBundle\IModel\User\UserInterface; | |||
use Lc\AdminBundle\Repository\BaseRepository; | |||
use Symfony\Component\Security\Core\Exception\UnsupportedUserException; | |||
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface; | |||
use Symfony\Component\Security\Core\User\UserInterface as SfUserInterface; | |||
/** | |||
* @method UserInterface|null find($id, $lockMode = null, $lockVersion = null) | |||
* @method UserInterface|null findOneBy(array $criteria, array $orderBy = null) | |||
* @method UserInterface[] findAll() | |||
* @method UserInterface[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||
*/ | |||
class UserRepository extends BaseRepository implements PasswordUpgraderInterface | |||
{ | |||
public function getInterfaceClass() | |||
{ | |||
return UserInterface::class; | |||
} | |||
/** | |||
* Used to upgrade (rehash) the user's password automatically over time. | |||
*/ | |||
public function upgradePassword(SfUserInterface $user, string $newEncodedPassword): void | |||
{ | |||
if (!$user instanceof SfUserInterface) { | |||
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user))); | |||
} | |||
$user->setPassword($newEncodedPassword); | |||
$this->_em->persist($user); | |||
$this->_em->flush(); | |||
} | |||
// /** | |||
// * @return User[] Returns an array of User objects | |||
// */ | |||
/* | |||
public function findByExampleField($value) | |||
{ | |||
return $this->createQueryBuilder('u') | |||
->andWhere('u.exampleField = :val') | |||
->setParameter('val', $value) | |||
->orderBy('u.id', 'ASC') | |||
->setMaxResults(10) | |||
->getQuery() | |||
->getResult() | |||
; | |||
} | |||
*/ | |||
/* | |||
public function findOneBySomeField($value): ?User | |||
{ | |||
return $this->createQueryBuilder('u') | |||
->andWhere('u.exampleField = :val') | |||
->setParameter('val', $value) | |||
->getQuery() | |||
->getOneOrNullResult() | |||
; | |||
} | |||
*/ | |||
} |