backports murph-skeleton
This commit is contained in:
parent
ced59844c4
commit
7698277368
|
@ -3,8 +3,8 @@
|
||||||
namespace App\Core\Controller\Admin;
|
namespace App\Core\Controller\Admin;
|
||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
abstract class AdminController extends AbstractController
|
abstract class AdminController extends AbstractController
|
||||||
{
|
{
|
||||||
|
|
172
core/Controller/Admin/Crud/CrudController.php
Normal file
172
core/Controller/Admin/Crud/CrudController.php
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Controller\Admin\Crud;
|
||||||
|
|
||||||
|
use App\Core\Controller\Admin\AdminController;
|
||||||
|
use App\Core\Crud\CrudConfiguration;
|
||||||
|
use App\Core\Entity\EntityInterface;
|
||||||
|
use App\Core\Manager\EntityManager;
|
||||||
|
use App\Core\Repository\RepositoryQuery;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CrudController.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
abstract class CrudController extends AdminController
|
||||||
|
{
|
||||||
|
protected array $filters = [];
|
||||||
|
|
||||||
|
abstract protected function getConfiguration(): CrudConfiguration;
|
||||||
|
|
||||||
|
protected function doIndex(int $page = 1, RepositoryQuery $query, Request $request, Session $session): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
|
||||||
|
$this->updateFilters($request, $session);
|
||||||
|
|
||||||
|
$pager = $query
|
||||||
|
->useFilters($this->filters)
|
||||||
|
->paginate($page, $configuration->getMaxPerPage('index'))
|
||||||
|
;
|
||||||
|
|
||||||
|
return $this->render($this->getConfiguration()->getView('index'), [
|
||||||
|
'configuration' => $configuration,
|
||||||
|
'pager' => $pager,
|
||||||
|
'filters' => [
|
||||||
|
'show' => null !== $configuration->getForm('filter'),
|
||||||
|
'isEmpty' => empty($this->filters),
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doNew(EntityInterface $entity, EntityManager $entityManager, Request $request): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
$form = $this->createForm($configuration->getForm('new'), $entity);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$entityManager->create($entity);
|
||||||
|
$this->addFlash('success', 'The data has been saved.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute($configuration->getPageRoute('edit'), [
|
||||||
|
'entity' => $entity->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->addFlash('warning', 'The form is not valid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render($configuration->getView('new'), [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'configuration' => $configuration,
|
||||||
|
'entity' => $entity,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doShow(EntityInterface $entity): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
|
||||||
|
return $this->render($configuration->getView('show'), [
|
||||||
|
'entity' => $entity,
|
||||||
|
'configuration' => $configuration,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doEdit(EntityInterface $entity, EntityManager $entityManager, Request $request): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
$form = $this->createForm($configuration->getForm('edit'), $entity);
|
||||||
|
|
||||||
|
if ($request->isMethod('POST')) {
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isValid()) {
|
||||||
|
$entityManager->update($entity);
|
||||||
|
$this->addFlash('success', 'The data has been saved.');
|
||||||
|
|
||||||
|
return $this->redirectToRoute($configuration->getPageRoute('edit'), [
|
||||||
|
'entity' => $entity->getId(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->addFlash('warning', 'The form is not valid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render($configuration->getView('edit'), [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'configuration' => $configuration,
|
||||||
|
'entity' => $entity,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
|
||||||
|
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
|
||||||
|
$entityManager->delete($entity);
|
||||||
|
|
||||||
|
$this->addFlash('success', 'The data has been removed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute($configuration->getPageRoute('index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function doFilter(Session $session): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
$type = $configuration->getForm('filter');
|
||||||
|
|
||||||
|
if (null === $type) {
|
||||||
|
throw $this->createNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm($type);
|
||||||
|
$form->submit($session->get($form->getName(), []));
|
||||||
|
|
||||||
|
return $this->render($configuration->getView('filter'), [
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'configuration' => $configuration,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updateFilters(Request $request, Session $session)
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
$type = $configuration->getForm('filter');
|
||||||
|
|
||||||
|
if (null === $type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form = $this->createForm($type);
|
||||||
|
|
||||||
|
if ($request->query->has($form->getName())) {
|
||||||
|
$filters = $request->query->get($form->getName());
|
||||||
|
|
||||||
|
if ('0' === $filters) {
|
||||||
|
$filters = [];
|
||||||
|
}
|
||||||
|
} elseif ($session->has($form->getName())) {
|
||||||
|
$filters = $session->get($form->getName());
|
||||||
|
} else {
|
||||||
|
$filters = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->submit($filters);
|
||||||
|
|
||||||
|
if (empty($filters)) {
|
||||||
|
$this->filters = $filters;
|
||||||
|
$session->set($form->getName(), $filters);
|
||||||
|
} elseif ($form->isValid()) {
|
||||||
|
$this->filters = $form->getData();
|
||||||
|
$session->set($form->getName(), $filters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ use App\Core\Event\Account\PasswordRequestEvent;
|
||||||
use App\Core\Manager\EntityManager;
|
use App\Core\Manager\EntityManager;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
@ -14,7 +15,6 @@ use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
|
use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||||
use ZxcvbnPhp\Zxcvbn;
|
use ZxcvbnPhp\Zxcvbn;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
|
||||||
|
|
||||||
class AuthController extends AbstractController
|
class AuthController extends AbstractController
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Core\Controller\Setting;
|
||||||
use App\Core\Controller\Admin\AdminController;
|
use App\Core\Controller\Admin\AdminController;
|
||||||
use App\Core\Entity\Setting as Entity;
|
use App\Core\Entity\Setting as Entity;
|
||||||
use App\Core\Event\Setting\SettingEvent;
|
use App\Core\Event\Setting\SettingEvent;
|
||||||
use App\Core\Factory\SettingFactory as EntityFactory;
|
|
||||||
use App\Core\Manager\EntityManager;
|
use App\Core\Manager\EntityManager;
|
||||||
use App\Core\Repository\SettingRepositoryQuery as RepositoryQuery;
|
use App\Core\Repository\SettingRepositoryQuery as RepositoryQuery;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
@ -47,8 +46,7 @@ class SettingAdminController extends AdminController
|
||||||
EntityManager $entityManager,
|
EntityManager $entityManager,
|
||||||
EventDispatcherInterface $eventDispatcher,
|
EventDispatcherInterface $eventDispatcher,
|
||||||
Request $request
|
Request $request
|
||||||
): Response
|
): Response {
|
||||||
{
|
|
||||||
$builder = $this->createFormBuilder($entity);
|
$builder = $this->createFormBuilder($entity);
|
||||||
|
|
||||||
$eventDispatcher->dispatch(new SettingEvent([
|
$eventDispatcher->dispatch(new SettingEvent([
|
||||||
|
|
|
@ -24,7 +24,8 @@ class NavigationAdminController extends AdminController
|
||||||
{
|
{
|
||||||
$pager = $query
|
$pager = $query
|
||||||
->orderBy('.label, .domain')
|
->orderBy('.label, .domain')
|
||||||
->paginate($page);
|
->paginate($page)
|
||||||
|
;
|
||||||
|
|
||||||
return $this->render('@Core/site/navigation_admin/index.html.twig', [
|
return $this->render('@Core/site/navigation_admin/index.html.twig', [
|
||||||
'pager' => $pager,
|
'pager' => $pager,
|
||||||
|
|
|
@ -5,17 +5,15 @@ namespace App\Core\Controller\Site;
|
||||||
use App\Core\Controller\Admin\AdminController;
|
use App\Core\Controller\Admin\AdminController;
|
||||||
use App\Core\Entity\Site\Page\Page as Entity;
|
use App\Core\Entity\Site\Page\Page as Entity;
|
||||||
use App\Core\Factory\Site\Page\PageFactory as EntityFactory;
|
use App\Core\Factory\Site\Page\PageFactory as EntityFactory;
|
||||||
use App\Core\Form\Site\Page\PageType as EntityType;
|
|
||||||
use App\Core\Form\Site\Page\Filter\PageFilterType as FilterType;
|
use App\Core\Form\Site\Page\Filter\PageFilterType as FilterType;
|
||||||
|
use App\Core\Form\Site\Page\PageType as EntityType;
|
||||||
use App\Core\Manager\EntityManager;
|
use App\Core\Manager\EntityManager;
|
||||||
use App\Core\Page\FooPage;
|
|
||||||
use App\Core\Page\SimplePage;
|
|
||||||
use App\Core\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
|
use App\Core\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
|
||||||
use App\Core\Site\PageLocator;
|
use App\Core\Site\PageLocator;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
use Symfony\Component\HttpFoundation\Session\Session;
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/admin/site/page")
|
* @Route("/admin/site/page")
|
||||||
|
@ -31,7 +29,8 @@ class PageAdminController extends AdminController
|
||||||
|
|
||||||
$pager = $query
|
$pager = $query
|
||||||
->useFilters($this->filters)
|
->useFilters($this->filters)
|
||||||
->paginate($page);
|
->paginate($page)
|
||||||
|
;
|
||||||
|
|
||||||
return $this->render('@Core/site/page_admin/index.html.twig', [
|
return $this->render('@Core/site/page_admin/index.html.twig', [
|
||||||
'pager' => $pager,
|
'pager' => $pager,
|
||||||
|
@ -39,24 +38,6 @@ class PageAdminController extends AdminController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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', 'The data has been saved.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('admin_site_page_edit', [
|
|
||||||
'entity' => $entity->getId(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/edit/{entity}", name="admin_site_page_edit")
|
* @Route("/edit/{entity}", name="admin_site_page_edit")
|
||||||
*/
|
*/
|
||||||
|
@ -122,6 +103,11 @@ class PageAdminController extends AdminController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getSection(): string
|
||||||
|
{
|
||||||
|
return 'site_page';
|
||||||
|
}
|
||||||
|
|
||||||
protected function updateFilters(Request $request, Session $session)
|
protected function updateFilters(Request $request, Session $session)
|
||||||
{
|
{
|
||||||
if ($request->query->has('page_filter')) {
|
if ($request->query->has('page_filter')) {
|
||||||
|
@ -147,9 +133,4 @@ class PageAdminController extends AdminController
|
||||||
$session->set('page_filter', $filters);
|
$session->set('page_filter', $filters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSection(): string
|
|
||||||
{
|
|
||||||
return 'site_page';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace App\Core\Controller\Site;
|
||||||
use App\Core\Site\SiteRequest;
|
use App\Core\Site\SiteRequest;
|
||||||
use App\Core\Site\SiteStore;
|
use App\Core\Site\SiteStore;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
class PageController extends AbstractController
|
class PageController extends AbstractController
|
||||||
|
|
|
@ -56,7 +56,8 @@ class TreeAdminController extends AdminController
|
||||||
): Response {
|
): Response {
|
||||||
$navigations = $navigationQuery->create()
|
$navigations = $navigationQuery->create()
|
||||||
->orderBy('.label, .domain')
|
->orderBy('.label, .domain')
|
||||||
->find();
|
->find()
|
||||||
|
;
|
||||||
|
|
||||||
$session->set('site_tree_last_navigation', $navigation->getId());
|
$session->set('site_tree_last_navigation', $navigation->getId());
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/admin/user")
|
* @Route("/admin/user")
|
||||||
|
@ -38,7 +37,6 @@ class UserAdminController extends AdminController
|
||||||
public function new(
|
public function new(
|
||||||
EntityFactory $factory,
|
EntityFactory $factory,
|
||||||
EntityManager $entityManager,
|
EntityManager $entityManager,
|
||||||
UserPasswordEncoderInterface $encoder,
|
|
||||||
Request $request
|
Request $request
|
||||||
): Response {
|
): Response {
|
||||||
$entity = $factory->create($this->getUser());
|
$entity = $factory->create($this->getUser());
|
||||||
|
|
164
core/Crud/CrudConfiguration.php
Normal file
164
core/Crud/CrudConfiguration.php
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CrudConfiguration.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class CrudConfiguration
|
||||||
|
{
|
||||||
|
protected array $pageTitles = [];
|
||||||
|
protected array $pageRoutes = [];
|
||||||
|
protected array $actions = [];
|
||||||
|
protected array $actionTitles = [];
|
||||||
|
protected array $forms = [];
|
||||||
|
protected array $formOptions = [];
|
||||||
|
protected array $views = [];
|
||||||
|
protected array $fields = [];
|
||||||
|
protected array $maxPerPage = [];
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setPageTitle(string $page, string $title): self
|
||||||
|
{
|
||||||
|
$this->pageTitles[$page] = $title;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageTitle(string $page, ?string $default = null): ?string
|
||||||
|
{
|
||||||
|
return $this->pageTitles[$page] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setPageRoute(string $page, string $route): self
|
||||||
|
{
|
||||||
|
$this->pageRoutes[$page] = $route;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageRoute(string $page): ?string
|
||||||
|
{
|
||||||
|
return $this->pageRoutes[$page];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setForm(string $context, string $form, array $options = []): self
|
||||||
|
{
|
||||||
|
$this->forms[$context] = $form;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getForm(string $context): ?string
|
||||||
|
{
|
||||||
|
return $this->forms[$context] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFormOptions(string $context, array $options = []): self
|
||||||
|
{
|
||||||
|
$this->formOptions[$context] = $options;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormOptions(string $context): array
|
||||||
|
{
|
||||||
|
return $this->formOptions[$context] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setAction(string $page, string $action, bool $enabled): self
|
||||||
|
{
|
||||||
|
if (!isset($this->actions[$page])) {
|
||||||
|
$this->actions[$page] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->actions[$page][$action] = $enabled;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAction(string $page, string $action, bool $default = true)
|
||||||
|
{
|
||||||
|
return $this->actions[$page][$action] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setActionTitle(string $page, string $action, string $title): self
|
||||||
|
{
|
||||||
|
if (!isset($this->actionTitles[$page])) {
|
||||||
|
$this->actionTitles[$page] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->actions[$page][$action] = $title;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionTitle(string $page, string $action, ?string $default = null): ?string
|
||||||
|
{
|
||||||
|
return $this->actionTitles[$page][$action] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setView(string $context, string $view): self
|
||||||
|
{
|
||||||
|
$this->views[$context] = $view;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getView(string $context, ?string $default = null)
|
||||||
|
{
|
||||||
|
if (null === $default) {
|
||||||
|
$default = sprintf('@Core/admin/crud/%s.html.twig', $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->views[$context] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setField(string $context, string $label, string $field, array $options): self
|
||||||
|
{
|
||||||
|
if (!isset($this->fields[$context])) {
|
||||||
|
$this->fields[$context] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->fields[$context][$label] = [
|
||||||
|
'field' => $field,
|
||||||
|
'options' => $options,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFields(string $context): array
|
||||||
|
{
|
||||||
|
return $this->fields[$context] ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- */
|
||||||
|
|
||||||
|
public function setMaxPerPage(string $page, int $max)
|
||||||
|
{
|
||||||
|
$this->maxPerPage[$page] = $max;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMaxPerPage(string $page, int $default = 20)
|
||||||
|
{
|
||||||
|
return $this->maxPerPage[$page] ?? $default;
|
||||||
|
}
|
||||||
|
}
|
12
core/Crud/Exception/CrudConfigurationException.php
Normal file
12
core/Crud/Exception/CrudConfigurationException.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class CrudConfigurationException.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class CrudConfigurationException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
29
core/Crud/Field/ButtonField.php
Normal file
29
core/Crud/Field/ButtonField.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Field;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class ButtonField.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class ButtonField extends Field
|
||||||
|
{
|
||||||
|
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||||
|
{
|
||||||
|
parent::configureOptions($resolver);
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'view' => '@Core/admin/crud/field/button.html.twig',
|
||||||
|
'button_attr' => [],
|
||||||
|
'button_tag' => 'button',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$resolver->setAllowedTypes('button_attr', ['array']);
|
||||||
|
$resolver->setAllowedTypes('button_tag', ['string']);
|
||||||
|
|
||||||
|
return $resolver;
|
||||||
|
}
|
||||||
|
}
|
25
core/Crud/Field/DateField.php
Normal file
25
core/Crud/Field/DateField.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Field;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class DateField.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class DateField extends Field
|
||||||
|
{
|
||||||
|
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||||
|
{
|
||||||
|
parent::configureOptions($resolver);
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'view' => '@Core/admin/crud/field/date.html.twig',
|
||||||
|
'format' => 'Y-m-d',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $resolver;
|
||||||
|
}
|
||||||
|
}
|
25
core/Crud/Field/DatetimeField.php
Normal file
25
core/Crud/Field/DatetimeField.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Field;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class DatetimeField.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class DatetimeField extends Field
|
||||||
|
{
|
||||||
|
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||||
|
{
|
||||||
|
parent::configureOptions($resolver);
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'view' => '@Core/admin/crud/field/date.html.twig',
|
||||||
|
'format' => 'Y-m-d H:i:s',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $resolver;
|
||||||
|
}
|
||||||
|
}
|
64
core/Crud/Field/Field.php
Normal file
64
core/Crud/Field/Field.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Field;
|
||||||
|
|
||||||
|
use App\Core\Crud\Exception\CrudConfigurationException;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
|
use Twig\Environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class Field.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
abstract class Field
|
||||||
|
{
|
||||||
|
public function buildView(Environment $twig, $entity, array $options)
|
||||||
|
{
|
||||||
|
return $twig->render($this->getView($options), [
|
||||||
|
'value' => $this->getValue($entity, $options),
|
||||||
|
'options' => $options,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'property' => null,
|
||||||
|
'property_builder' => null,
|
||||||
|
'view' => null,
|
||||||
|
'attr' => [],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$resolver->setRequired('view');
|
||||||
|
$resolver->setAllowedTypes('property', ['null', 'string']);
|
||||||
|
$resolver->setAllowedTypes('view', 'string');
|
||||||
|
$resolver->setAllowedTypes('attr', 'array');
|
||||||
|
$resolver->setAllowedTypes('property_builder', ['null', 'callable']);
|
||||||
|
|
||||||
|
return $resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getValue($entity, array $options)
|
||||||
|
{
|
||||||
|
$propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
|
||||||
|
->getPropertyAccessor()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (null !== $options['property']) {
|
||||||
|
$value = $propertyAccessor->getValue($entity, $options['property']);
|
||||||
|
} elseif (null !== $options['property_builder']) {
|
||||||
|
$value = call_user_func($options['property_builder'], $entity, $options);
|
||||||
|
} else {
|
||||||
|
throw new CrudConfigurationException('Unable to get the value. One of "property" and "property_builder" is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getView(array $options)
|
||||||
|
{
|
||||||
|
return $options['view'];
|
||||||
|
}
|
||||||
|
}
|
24
core/Crud/Field/TextField.php
Normal file
24
core/Crud/Field/TextField.php
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Crud\Field;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class TextField.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
class TextField extends Field
|
||||||
|
{
|
||||||
|
public function configureOptions(OptionsResolver $resolver): OptionsResolver
|
||||||
|
{
|
||||||
|
parent::configureOptions($resolver);
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'view' => '@Core/admin/crud/field/text.html.twig',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $resolver;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
*/
|
*/
|
||||||
abstract class EntityManagerEventSubscriber implements EventSubscriberInterface
|
abstract class EntityManagerEventSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
static protected int $priority = 0;
|
protected static int $priority = 0;
|
||||||
|
|
||||||
public static function getSubscribedEvents()
|
public static function getSubscribedEvents()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Core\EventSuscriber\Site;
|
namespace App\Core\EventSuscriber\Site;
|
||||||
|
|
||||||
|
use App\Core\Cache\SymfonyCacheManager;
|
||||||
use App\Core\Entity\EntityInterface;
|
use App\Core\Entity\EntityInterface;
|
||||||
use App\Core\Entity\Site\Menu;
|
use App\Core\Entity\Site\Menu;
|
||||||
use App\Core\Event\EntityManager\EntityManagerEvent;
|
use App\Core\Event\EntityManager\EntityManagerEvent;
|
||||||
|
@ -10,7 +11,6 @@ use App\Core\Factory\Site\NodeFactory;
|
||||||
use App\Core\Manager\EntityManager;
|
use App\Core\Manager\EntityManager;
|
||||||
use App\Core\Repository\Site\NodeRepository;
|
use App\Core\Repository\Site\NodeRepository;
|
||||||
use App\Core\Slugify\CodeSlugify;
|
use App\Core\Slugify\CodeSlugify;
|
||||||
use App\Core\Cache\SymfonyCacheManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class MenuEventSubscriber.
|
* class MenuEventSubscriber.
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
|
|
||||||
namespace App\Core\EventSuscriber\Site;
|
namespace App\Core\EventSuscriber\Site;
|
||||||
|
|
||||||
|
use App\Core\Cache\SymfonyCacheManager;
|
||||||
use App\Core\Entity\EntityInterface;
|
use App\Core\Entity\EntityInterface;
|
||||||
use App\Core\Entity\Site\Menu;
|
use App\Core\Entity\Site\Menu;
|
||||||
use App\Core\Entity\Site\Navigation;
|
use App\Core\Entity\Site\Navigation;
|
||||||
use App\Core\Entity\Site\Node;
|
use App\Core\Entity\Site\Node;
|
||||||
use App\Core\Event\EntityManager\EntityManagerEvent;
|
use App\Core\Event\EntityManager\EntityManagerEvent;
|
||||||
use App\Core\EventSuscriber\EntityManagerEventSubscriber;
|
use App\Core\EventSuscriber\EntityManagerEventSubscriber;
|
||||||
use Symfony\Component\Finder\Finder;
|
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use App\Core\Cache\SymfonyCacheManager;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class SiteEventSubscriber.
|
* class SiteEventSubscriber.
|
||||||
|
|
12
core/Factory/FactoryInterface.php
Normal file
12
core/Factory/FactoryInterface.php
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interface FactoryInterface.
|
||||||
|
*
|
||||||
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
|
*/
|
||||||
|
interface FactoryInterface
|
||||||
|
{
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ use App\Core\Entity\Setting;
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class SettingFactory
|
class SettingFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(string $code): Setting
|
public function create(string $code): Setting
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,13 +4,14 @@ namespace App\Core\Factory\Site;
|
||||||
|
|
||||||
use App\Core\Entity\Site\Menu;
|
use App\Core\Entity\Site\Menu;
|
||||||
use App\Core\Entity\Site\Navigation;
|
use App\Core\Entity\Site\Navigation;
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class MenuFactory.
|
* class MenuFactory.
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class MenuFactory
|
class MenuFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(?Navigation $navigation = null): Menu
|
public function create(?Navigation $navigation = null): Menu
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
namespace App\Core\Factory\Site;
|
namespace App\Core\Factory\Site;
|
||||||
|
|
||||||
use App\Core\Entity\Site\Navigation;
|
use App\Core\Entity\Site\Navigation;
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class NavigationFactory.
|
* class NavigationFactory.
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class NavigationFactory
|
class NavigationFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(): Navigation
|
public function create(): Navigation
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,13 +4,14 @@ namespace App\Core\Factory\Site;
|
||||||
|
|
||||||
use App\Core\Entity\Site\Menu;
|
use App\Core\Entity\Site\Menu;
|
||||||
use App\Core\Entity\Site\Node;
|
use App\Core\Entity\Site\Node;
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class NodeFactory.
|
* class NodeFactory.
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class NodeFactory
|
class NodeFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(?Menu $menu = null, string $url = null): Node
|
public function create(?Menu $menu = null, string $url = null): Node
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
namespace App\Core\Factory\Site\Page;
|
namespace App\Core\Factory\Site\Page;
|
||||||
|
|
||||||
use App\Core\Entity\Site\Page\Page;
|
use App\Core\Entity\Site\Page\Page;
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class PageFactory.
|
* class PageFactory.
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class PageFactory
|
class PageFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(string $className, string $name): Page
|
public function create(string $className, string $name): Page
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface;
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class UserFactory
|
class UserFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
protected TokenGeneratorInterface $tokenGenerator;
|
protected TokenGeneratorInterface $tokenGenerator;
|
||||||
protected UserPasswordEncoderInterface $encoder;
|
protected UserPasswordEncoderInterface $encoder;
|
||||||
|
|
|
@ -7,8 +7,8 @@ use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
|
||||||
use Symfony\Component\Validator\Constraints\Length;
|
use Symfony\Component\Validator\Constraints\Length;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||||
|
|
||||||
class NavigationType extends AbstractType
|
class NavigationType extends AbstractType
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,18 +2,13 @@
|
||||||
|
|
||||||
namespace App\Core\Form\Site\Page\Filter;
|
namespace App\Core\Form\Site\Page\Filter;
|
||||||
|
|
||||||
use App\Core\Entity\Site\Page\Page;
|
use App\Core\Entity\Site\Navigation;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Validator\Constraints\Image;
|
|
||||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
|
||||||
use App\Core\Entity\Site\Navigation;
|
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
|
|
||||||
class PageFilterType extends AbstractType
|
class PageFilterType extends AbstractType
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,27 @@ abstract class RepositoryQuery
|
||||||
return $this->repository;
|
return $this->repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function useFilters(array $filters)
|
||||||
|
{
|
||||||
|
foreach ($filters as $name => $value) {
|
||||||
|
if (null === $value) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_int($value) || is_bool($value)) {
|
||||||
|
$this->andWhere('.'.$name.' = :'.$name);
|
||||||
|
$this->setParameter(':'.$name, $value);
|
||||||
|
} elseif (is_string($value)) {
|
||||||
|
$this->andWhere('.'.$name.' LIKE :'.$name);
|
||||||
|
$this->setParameter(':'.$name, '%'.$value.'%');
|
||||||
|
} else {
|
||||||
|
$this->filterHandler($name, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function populateDqlId(&$data)
|
protected function populateDqlId(&$data)
|
||||||
{
|
{
|
||||||
if (is_string($data)) {
|
if (is_string($data)) {
|
||||||
|
@ -98,25 +119,4 @@ abstract class RepositoryQuery
|
||||||
protected function filterHandler(string $name, $value)
|
protected function filterHandler(string $name, $value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function useFilters(array $filters)
|
|
||||||
{
|
|
||||||
foreach ($filters as $name => $value) {
|
|
||||||
if (null === $value) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_int($value) || is_bool($value)) {
|
|
||||||
$this->andWhere('.'.$name.' = :'.$name);
|
|
||||||
$this->setParameter(':'.$name, $value);
|
|
||||||
} elseif (is_string($value)) {
|
|
||||||
$this->andWhere('.'.$name.' LIKE :'.$name);
|
|
||||||
$this->setParameter(':'.$name, '%'.$value.'%');
|
|
||||||
} else {
|
|
||||||
$this->filterHandler($name, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
namespace App\Core\Repository\Site\Page;
|
namespace App\Core\Repository\Site\Page;
|
||||||
|
|
||||||
|
use App\Core\Entity\Site\Navigation;
|
||||||
use App\Core\Repository\RepositoryQuery;
|
use App\Core\Repository\RepositoryQuery;
|
||||||
use Knp\Component\Pager\PaginatorInterface;
|
use Knp\Component\Pager\PaginatorInterface;
|
||||||
use App\Core\Entity\Site\Navigation;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class PageRepositoryQuery.
|
* class PageRepositoryQuery.
|
||||||
|
@ -18,15 +18,6 @@ class PageRepositoryQuery extends RepositoryQuery
|
||||||
parent::__construct($repository, 'p', $paginator);
|
parent::__construct($repository, 'p', $paginator);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function filterHandler(string $name, $value)
|
|
||||||
{
|
|
||||||
if ($name === 'navigation') {
|
|
||||||
return $this->filterByNavigation($value);
|
|
||||||
} else {
|
|
||||||
return parent::filterHandler($name, $value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function filterByNavigation(Navigation $navigation)
|
public function filterByNavigation(Navigation $navigation)
|
||||||
{
|
{
|
||||||
return $this
|
return $this
|
||||||
|
@ -34,7 +25,8 @@ class PageRepositoryQuery extends RepositoryQuery
|
||||||
->leftJoin('node.menu', 'menu')
|
->leftJoin('node.menu', 'menu')
|
||||||
->leftJoin('menu.navigation', 'navigation')
|
->leftJoin('menu.navigation', 'navigation')
|
||||||
->where('navigation.id = :navigationId')
|
->where('navigation.id = :navigationId')
|
||||||
->setParameter(':navigationId', $navigation->getId());
|
->setParameter(':navigationId', $navigation->getId())
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function filterById($id)
|
public function filterById($id)
|
||||||
|
@ -46,4 +38,13 @@ class PageRepositoryQuery extends RepositoryQuery
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function filterHandler(string $name, $value)
|
||||||
|
{
|
||||||
|
if ('navigation' === $name) {
|
||||||
|
return $this->filterByNavigation($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::filterHandler($name, $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@
|
||||||
"Add a menu": "Ajouter un menu"
|
"Add a menu": "Ajouter un menu"
|
||||||
"Actions": "Actions"
|
"Actions": "Actions"
|
||||||
"Remove": "Supprimer"
|
"Remove": "Supprimer"
|
||||||
|
"Delete": "Supprimer"
|
||||||
"Move": "Déplacer"
|
"Move": "Déplacer"
|
||||||
"Hidden": "Caché"
|
"Hidden": "Caché"
|
||||||
"Show": "Voir"
|
"Show": "Voir"
|
||||||
|
@ -126,9 +127,13 @@
|
||||||
"Name": "Nom"
|
"Name": "Nom"
|
||||||
"Authentication": "Authentification"
|
"Authentication": "Authentification"
|
||||||
"Anyway": "Peu importe"
|
"Anyway": "Peu importe"
|
||||||
|
"Reset": "Réinitialiser"
|
||||||
"Yes": "Oui"
|
"Yes": "Oui"
|
||||||
"No": "Non"
|
"No": "Non"
|
||||||
|
"yes": "oui"
|
||||||
|
"no": "non"
|
||||||
"Locale": "Langue"
|
"Locale": "Langue"
|
||||||
"Settings": "Paramètres"
|
"Settings": "Paramètres"
|
||||||
"Setting": "Paramètre"
|
"Setting": "Paramètre"
|
||||||
"Section": "Section"
|
"Section": "Section"
|
||||||
|
"Filter": "Filtrer"
|
||||||
|
|
6
core/Resources/views/admin/crud/_form.html.twig
Normal file
6
core/Resources/views/admin/crud/_form.html.twig
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
1
core/Resources/views/admin/crud/_show.html.twig
Normal file
1
core/Resources/views/admin/crud/_show.html.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<p>{{ '{__toString}'|build_string(entity) }}</p>
|
88
core/Resources/views/admin/crud/edit.html.twig
Normal file
88
core/Resources/views/admin/crud/edit.html.twig
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
{% extends '@Core/admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ configuration.pageTitle('edit')|trans|build_string(entity) }} - {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% block header %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="crud-header">
|
||||||
|
{% block header_title %}
|
||||||
|
<h1 class="crud-header-title">{{ configuration.pageTitle('edit')|trans|build_string(entity) }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_actions %}
|
||||||
|
<div class="crud-header-actions">
|
||||||
|
<div class="btn-group">
|
||||||
|
{% if configuration.action('edit', 'back', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('index')) }}" class="btn btn-light">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('edit', 'back', 'Back to the list')|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if configuration.action('edit', 'show', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('show'), {entity: entity.id}) }}" class="btn btn-secondary">
|
||||||
|
<span class="fa fa-eye pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('edit', 'show', 'Show')|trans|build_string(entity) }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<button type="submit" form="form-main" class="btn btn-primary">
|
||||||
|
<span class="fa fa-save pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('edit', 'save', 'Save')|trans|build_string(entity) }}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{% block dropdownMenu %}
|
||||||
|
{% set menu = '' %}
|
||||||
|
|
||||||
|
{% if configuration.action('edit', 'delete', true) %}
|
||||||
|
{% set item %}
|
||||||
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
|
<button type="submit" form="form-delete" class="dropdown-item">
|
||||||
|
{{ configuration.actionTitle('edit', 'delete', 'Delete')|trans|build_string(entity) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{% endset %}
|
||||||
|
|
||||||
|
{% set menu = menu ~ item %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if menu %}
|
||||||
|
<button type="button" class="btn btn-white dropdown-toggle dropdown-toggle-hide-after" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="font-weight-bold">
|
||||||
|
⋅⋅⋅
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{{ menu|raw }}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block form %}
|
||||||
|
<form action="{{ app.request.uri }}" method="post" id="form-main" enctype="multipart/form-data">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active">
|
||||||
|
<div class="tab-form">
|
||||||
|
{{ include(configuration.view('editForm', '@Core/admin/crud/_form.html.twig')) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% if configuration.action('edit', 'delete', true) %}
|
||||||
|
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: entity.id}) }}" id="form-delete" data-form-confirm>
|
||||||
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ entity.id) }}">
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
1
core/Resources/views/admin/crud/field/button.html.twig
Normal file
1
core/Resources/views/admin/crud/field/button.html.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<{{ options.button_tag }} {% for k, v in options.button_attr %}{{ k }}="{{ v }}"{% endfor %}>{{ value }}</{{ options.button_tag }}>
|
1
core/Resources/views/admin/crud/field/date.html.twig
Normal file
1
core/Resources/views/admin/crud/field/date.html.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{ value|date(options.format) }}
|
1
core/Resources/views/admin/crud/field/text.html.twig
Normal file
1
core/Resources/views/admin/crud/field/text.html.twig
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{{ value }}
|
21
core/Resources/views/admin/crud/filter.html.twig
Normal file
21
core/Resources/views/admin/crud/filter.html.twig
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">
|
||||||
|
{{ 'Filter'|trans }}
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form action="{{ path(configuration.pageRoute('index')) }}" id="form-filters" method="GET">
|
||||||
|
{{ form_widget(form) }}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<a href="{{ path(configuration.pageRoute('index'), {(form.vars.name): 0}) }}" class="btn btn-secondary">{{ 'Reset'|trans }}</a>
|
||||||
|
<button type="submit" form="form-filters" class="btn btn-primary">{{ 'Filter'|trans }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
127
core/Resources/views/admin/crud/index.html.twig
Normal file
127
core/Resources/views/admin/crud/index.html.twig
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
{% extends '@Core/admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ configuration.pageTitle('index')|trans }} - {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% block header %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 {% if pager.paginationData.pageCount < 2 %}{% if filters.show %}pb-3{% else %}pb-5{% endif %}{% endif %}">
|
||||||
|
<div class="crud-header">
|
||||||
|
{% block header_title %}
|
||||||
|
<h1 class="crud-header-title">{{ configuration.pageTitle('index')|trans }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_actions %}
|
||||||
|
<div class="crud-header-actions">
|
||||||
|
<div class="btn-group">
|
||||||
|
{% if configuration.action('index', 'new', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('new')) }}" class="btn btn-primary">
|
||||||
|
<span class="fa fa-plus pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('index', 'new', 'New')|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block header_filter_pager %}
|
||||||
|
{% if filters.show %}
|
||||||
|
<div class="row pb-3">
|
||||||
|
<div class="col-auto ml-auto {% if pager.getPaginationData.pageCount > 1 %}mr-3{% endif %}">
|
||||||
|
<button data-modal="{{ path(configuration.pageRoute('filter')) }}" class="btn btn-sm btn-secondary">
|
||||||
|
{{ 'Filter'|trans }} {% if not filters.isEmpty %}({{ 'yes'|trans }}){% endif %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
{{ knp_pagination_render(pager) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
{{ knp_pagination_render(pager) }}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block list %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table">
|
||||||
|
{% block list_header %}
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
{% for label, config in configuration.fields('index') %}
|
||||||
|
{% set attr = config.options.attr is defined ? config.options.attr : [] %}
|
||||||
|
|
||||||
|
<th {% for key, value in attr %}{{ key }}="{{ value }}"{% endfor %}>
|
||||||
|
{{ label|trans }}
|
||||||
|
</th>
|
||||||
|
{% endfor %}
|
||||||
|
<th class="col-2 miw-100 text-right">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block list_items %}
|
||||||
|
<tbody>
|
||||||
|
{% for item in pager %}
|
||||||
|
{% block list_item %}
|
||||||
|
<tr data-dblclick="">
|
||||||
|
{% for config in configuration.fields('index') %}
|
||||||
|
{% set attr = config.options.attr is defined ? config.options.attr : [] %}
|
||||||
|
{% set action = config.options.action is defined ? config.options.action : null %}
|
||||||
|
|
||||||
|
<td {% for key, value in attr %}{{ key }}="{{ value }}"{% endfor %}>
|
||||||
|
{% if action == 'show' %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('show'), {entity: item.id}) }}">
|
||||||
|
{{ render_field(item, config) }}
|
||||||
|
</a>
|
||||||
|
{% elseif action == 'edit' %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}) }}">
|
||||||
|
{{ render_field(item, config) }}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
{{ render_field(item, config) }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if configuration.action('index', 'edit', true) or configuration.action('index', 'delete', true) %}
|
||||||
|
<td class="col-2 miw-100 text-right">
|
||||||
|
{% if configuration.action('index', 'edit', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}) }}" class="btn btn-sm btn-primary mr-1">
|
||||||
|
<span class="fa fa-edit"></span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if configuration.action('index', 'delete', true) %}
|
||||||
|
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
|
||||||
|
<span class="fa fa-trash"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: item.id}) }}" id="form-delete-{{ item.id }}" data-form-confirm>
|
||||||
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
{% endblock %}
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td class="col-12 text-center p-4 text-black-50" colspan="{{ configuration.fields('index')|length + 1 }}">
|
||||||
|
<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>
|
||||||
|
{% endblock %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
47
core/Resources/views/admin/crud/new.html.twig
Normal file
47
core/Resources/views/admin/crud/new.html.twig
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{% extends '@Core/admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ configuration.pageTitle('new')|trans|build_string(entity) }} - {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% block header %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="crud-header">
|
||||||
|
{% block header_title %}
|
||||||
|
<h1 class="crud-header-title">{{ configuration.pageTitle('new')|trans|build_string(entity) }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_actions %}
|
||||||
|
<div class="crud-header-actions">
|
||||||
|
<div class="btn-group">
|
||||||
|
{% if configuration.action('new', 'back', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('index')) }}" class="btn btn-light">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('new', 'back', 'Back to the list')|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<button type="submit" form="form-main" class="btn btn-primary">
|
||||||
|
<span class="fa fa-save pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('new', 'save', 'Save')|trans|build_string(entity) }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block form %}
|
||||||
|
<form action="{{ app.request.uri }}" method="post" id="form-main" enctype="multipart/form-data">
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active">
|
||||||
|
<div class="tab-form">
|
||||||
|
{{ include(configuration.view('newForm', '@Core/admin/crud/_form.html.twig')) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_rest(form) }}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
44
core/Resources/views/admin/crud/show.html.twig
Normal file
44
core/Resources/views/admin/crud/show.html.twig
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
{% extends '@Core/admin/layout.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ configuration.pageTitle('show')|trans|build_string(entity) }} - {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
{% block header %}
|
||||||
|
<div class="bg-light pl-5 pr-4 pt-5 pb-5">
|
||||||
|
<div class="crud-header">
|
||||||
|
{% block header_title %}
|
||||||
|
<h1 class="crud-header-title">{{ configuration.pageTitle('show')|trans|build_string(entity) }}</h1>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block header_actions %}
|
||||||
|
<div class="crud-header-actions">
|
||||||
|
<div class="btn-group">
|
||||||
|
{% if configuration.action('show', 'back', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('index')) }}" class="btn btn-light">
|
||||||
|
<span class="fa fa-list pr-1"></span>
|
||||||
|
{{ configuration.actionTitle('show', 'back', 'Back to the list')|trans }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if configuration.action('show', 'edit', true) %}
|
||||||
|
<a href="{{ path(configuration.pageRoute('edit'), {entity: entity.id}) }}" class="btn btn-primary">
|
||||||
|
<span class="fa fa-edit pr-1"></span>
|
||||||
|
|
||||||
|
{{ configuration.actionTitle('show', 'edit', 'Edit')|trans|build_string(entity) }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block show %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12 p-3">
|
||||||
|
{{ include(configuration.view('showEntity', '@Core/admin/crud/_show.html.twig')) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace App\Core\Setting;
|
namespace App\Core\Setting;
|
||||||
|
|
||||||
|
use App\Core\Entity\Setting;
|
||||||
use App\Core\Factory\SettingFactory;
|
use App\Core\Factory\SettingFactory;
|
||||||
use App\Core\Manager\EntityManager;
|
use App\Core\Manager\EntityManager;
|
||||||
use App\Core\Repository\SettingRepositoryQuery;
|
use App\Core\Repository\SettingRepositoryQuery;
|
||||||
use App\Core\Entity\Setting;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class SettingManager.
|
* class SettingManager.
|
||||||
|
|
|
@ -18,6 +18,7 @@ class StringBuilder
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
|
$this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
|
||||||
|
->disableExceptionOnInvalidPropertyPath()
|
||||||
->getPropertyAccessor()
|
->getPropertyAccessor()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -33,12 +34,12 @@ class StringBuilder
|
||||||
return $format;
|
return $format;
|
||||||
}
|
}
|
||||||
|
|
||||||
preg_match_all('/\{([a-zA-Z0-9\.]+)\}/i', $format, $matches, PREG_SET_ORDER);
|
preg_match_all('/\{([a-zA-Z0-9\._]+)\}/i', $format, $matches, PREG_SET_ORDER);
|
||||||
|
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
$propertyValue = $this->propertyAccessor->getValue($object, $match[1]);
|
$propertyValue = $this->propertyAccessor->getValue($object, $match[1]);
|
||||||
|
|
||||||
$format = u($format)->replace($match[0], $propertyValue);
|
$format = u($format)->replace($match[0], (string) $propertyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $format;
|
return $format;
|
||||||
|
|
44
core/Twig/Extension/CrudExtension.php
Normal file
44
core/Twig/Extension/CrudExtension.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Core\Twig\Extension;
|
||||||
|
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
||||||
|
use Twig\Environment;
|
||||||
|
use Twig\Extension\AbstractExtension;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
|
class CrudExtension extends AbstractExtension
|
||||||
|
{
|
||||||
|
protected PropertyAccessor $propertyAccessor;
|
||||||
|
protected Environment $twig;
|
||||||
|
|
||||||
|
public function __construct(Environment $twig)
|
||||||
|
{
|
||||||
|
$this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
|
||||||
|
->getPropertyAccessor()
|
||||||
|
;
|
||||||
|
|
||||||
|
$this->twig = $twig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getFunctions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
new TwigFunction('render_field', [$this, 'renderField'], ['is_safe' => ['html']]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderField($entity, array $config): string
|
||||||
|
{
|
||||||
|
$field = $config['field'];
|
||||||
|
$instance = new $field();
|
||||||
|
$resolver = $instance->configureOptions(new OptionsResolver());
|
||||||
|
|
||||||
|
return $instance->buildView($this->twig, $entity, $resolver->resolve($config['options']));
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Factory\Blog;
|
namespace App\Factory\Blog;
|
||||||
|
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
use App\Entity\Blog\Category;
|
use App\Entity\Blog\Category;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +10,7 @@ use App\Entity\Blog\Category;
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class CategoryFactory
|
class CategoryFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(): Category
|
public function create(): Category
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Factory\Blog;
|
namespace App\Factory\Blog;
|
||||||
|
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
use App\Entity\Blog\Comment;
|
use App\Entity\Blog\Comment;
|
||||||
use App\Entity\Blog\Post;
|
use App\Entity\Blog\Post;
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ use App\Entity\Blog\Post;
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class CommentFactory
|
class CommentFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(Post $post): Comment
|
public function create(Post $post): Comment
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Factory\Blog;
|
namespace App\Factory\Blog;
|
||||||
|
|
||||||
|
use App\Core\Factory\FactoryInterface;
|
||||||
use App\Entity\Blog\Post;
|
use App\Entity\Blog\Post;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +10,7 @@ use App\Entity\Blog\Post;
|
||||||
*
|
*
|
||||||
* @author Simon Vieille <simon@deblan.fr>
|
* @author Simon Vieille <simon@deblan.fr>
|
||||||
*/
|
*/
|
||||||
class PostFactory
|
class PostFactory implements FactoryInterface
|
||||||
{
|
{
|
||||||
public function create(): Post
|
public function create(): Post
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue