add navigation setting

This commit is contained in:
Simon Vieille 2021-05-28 10:43:52 +02:00
parent 9b5cee2e03
commit 92887b029e
15 changed files with 592 additions and 33 deletions

View File

@ -0,0 +1,78 @@
<?php
namespace App\Core\Controller\Setting;
use App\Core\Controller\Admin\AdminController;
use App\Core\Entity\NavigationSetting as Entity;
use App\Core\Event\Setting\NavigationSettingEvent;
use App\Core\Manager\EntityManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/admin/navigation_setting")
*/
class NavigationSettingAdminController extends AdminController
{
/**
* @Route("/edit/{entity}", name="admin_navigation_setting_edit")
*/
public function edit(
Entity $entity,
EntityManager $entityManager,
EventDispatcherInterface $eventDispatcher,
Request $request
): Response {
$builder = $this->createFormBuilder($entity);
$eventDispatcher->dispatch(new NavigationSettingEvent([
'builder' => $builder,
'entity' => $entity,
]), NavigationSettingEvent::FORM_INIT_EVENT);
$form = $builder->getForm();
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$entityManager->update($entity);
$this->addFlash('success', 'The data has been saved.');
return $this->redirectToRoute('admin_site_navigation_show', [
'entity' => $entity->getNavigation()->getId(),
]);
}
$this->addFlash('warning', 'The form is not valid.');
}
return $this->render('@Core/setting/navigation_setting_admin/edit.html.twig', [
'form' => $form->createView(),
'entity' => $entity,
]);
}
/**
* @Route("/delete/{entity}", name="admin_navigation_setting_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'The data has been removed.');
}
return $this->redirectToRoute('admin_site_navigation_show', [
'entity' => $entity->getNavigation()->getId(),
]);
}
public function getSection(): string
{
return '';
}
}

View File

@ -6,10 +6,13 @@ use App\Core\Controller\Admin\Crud\CrudController;
use App\Core\Crud\CrudConfiguration;
use App\Core\Crud\Field;
use App\Core\Entity\Site\Navigation as Entity;
use App\Core\Event\Setting\NavigationSettingEvent;
use App\Core\Factory\Site\NavigationFactory as Factory;
use App\Core\Form\Site\NavigationType as Type;
use App\Core\Manager\EntityManager;
use App\Core\Repository\NavigationSettingRepositoryQuery;
use App\Core\Repository\Site\NavigationRepositoryQuery as RepositoryQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
@ -36,8 +39,24 @@ class NavigationAdminController extends CrudController
/**
* @Route("/admin/site/navigation/show/{entity}", name="admin_site_navigation_show", methods={"GET"})
*/
public function show(Entity $entity): Response
{
public function show(
Entity $entity,
EventDispatcherInterface $eventDispatcher,
NavigationSettingRepositoryQuery $settingQuery
): Response {
$eventDispatcher->dispatch(new NavigationSettingEvent([
'navigation' => $entity,
]), NavigationSettingEvent::INIT_EVENT);
$settings = $settingQuery
->where('.navigation = :navigation')
->orderBy('.section, .label')
->setParameter(':navigation', $entity->getId())
->paginate(1, 1000)
;
$this->getConfiguration()->addViewData('show', 'settings', $settings);
return $this->doShow($entity);
}

View File

@ -0,0 +1,111 @@
<?php
namespace App\Core\Entity;
use App\Core\Entity\Site\Navigation;
use App\Core\Repository\NavigationSettingRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=NavigationSettingRepository::class)
*/
class NavigationSetting implements EntityInterface
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $section;
/**
* @ORM\Column(type="string", length=255)
*/
private $label;
/**
* @ORM\Column(type="string", length=255)
*/
private $code;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $value;
/**
* @ORM\ManyToOne(targetEntity=Navigation::class, inversedBy="navigationSettings")
* @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
*/
private $navigation;
public function getId(): ?int
{
return $this->id;
}
public function getSection(): ?string
{
return $this->section;
}
public function setSection(string $section): self
{
$this->section = $section;
return $this;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(string $label): self
{
$this->label = $label;
return $this;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
public function getValue()
{
return json_decode($this->value, true);
}
public function setValue($value): self
{
$this->value = json_encode($value);
return $this;
}
public function getNavigation(): ?Navigation
{
return $this->navigation;
}
public function setNavigation(?Navigation $navigation): self
{
$this->navigation = $navigation;
return $this;
}
}

View File

@ -4,6 +4,7 @@ namespace App\Core\Entity\Site;
use App\Core\Doctrine\Timestampable;
use App\Core\Entity\EntityInterface;
use App\Core\Entity\NavigationSetting;
use App\Core\Repository\Site\NavigationRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
@ -64,9 +65,15 @@ class Navigation implements EntityInterface
*/
private $sortOrder;
/**
* @ORM\OneToMany(targetEntity=NavigationSetting::class, mappedBy="navigation", orphanRemoval=true)
*/
private $navigationSettings;
public function __construct()
{
$this->menus = new ArrayCollection();
$this->navigationSettings = new ArrayCollection();
}
public function getId(): ?int
@ -203,4 +210,34 @@ class Navigation implements EntityInterface
return $this;
}
/**
* @return Collection|NavigationSetting[]
*/
public function getNavigationSettings(): Collection
{
return $this->navigationSettings;
}
public function addNavigationSetting(NavigationSetting $navigationSetting): self
{
if (!$this->navigationSettings->contains($navigationSetting)) {
$this->navigationSettings[] = $navigationSetting;
$navigationSetting->setNavigation($this);
}
return $this;
}
public function removeNavigationSetting(NavigationSetting $navigationSetting): self
{
if ($this->navigationSettings->removeElement($navigationSetting)) {
// set the owning side to null (unless already changed)
if ($navigationSetting->getNavigation() === $this) {
$navigationSetting->setNavigation(null);
}
}
return $this;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Core\Event\Setting;
use Symfony\Contracts\EventDispatcher\Event;
/**
* class NavigationSettingEvent.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationSettingEvent extends Event
{
const INIT_EVENT = 'navigation_setting_event.init';
const FORM_INIT_EVENT = 'navigation_setting_event.form_init';
protected $data;
public function __construct($data = null)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace App\Core\EventSuscriber;
use App\Core\Event\Setting\NavigationSettingEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* class NavigationSettingEventSubscriber.
*
* @author Simon Vieille <simon@deblan.fr>
*/
abstract class NavigationSettingEventSubscriber implements EventSubscriberInterface
{
protected static int $priority = 0;
public static function getSubscribedEvents()
{
return [
NavigationSettingEvent::INIT_EVENT => ['onInit', self::$priority],
NavigationSettingEvent::FORM_INIT_EVENT => ['onFormInit', self::$priority],
];
}
public function onInit(NavigationSettingEvent $event)
{
}
public function onFormInit(NavigationSettingEvent $event)
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Core\Factory;
use App\Core\Entity\NavigationSetting;
use App\Core\Entity\Site\Navigation;
/**
* class NavigationSettingFactory.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationSettingFactory implements FactoryInterface
{
public function create(Navigation $navigation, string $code): NavigationSetting
{
$entity = new NavigationSetting();
$entity
->setNavigation($navigation)
->setCode($code);
return $entity;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Core\Repository;
use App\Core\Entity\NavigationSetting;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method NavigationSetting|null find($id, $lockMode = null, $lockVersion = null)
* @method NavigationSetting|null findOneBy(array $criteria, array $orderBy = null)
* @method NavigationSetting[] findAll()
* @method NavigationSetting[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class NavigationSettingRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, NavigationSetting::class);
}
}

View File

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

View File

@ -0,0 +1,5 @@
<div class="row">
<div class="col-md-12">
{{ form_widget(form) }}
</div>
</div>

View File

@ -0,0 +1,20 @@
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ entity.section|trans }}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="{{ path('admin_navigation_setting_edit', {entity: entity.id}) }}" id="form-entity-edit" method="POST">
{{ include('@Core/setting/navigation_setting_admin/_form.html.twig') }}
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Cancel'|trans }}</button>
<button type="submit" form="form-entity-edit" class="btn btn-primary">{{ 'Save'|trans }}</button>
</div>
</div>
</div>

View File

@ -1,32 +1,33 @@
{% set datas = configuration.viewDatas(context) %}
<div class="row">
<div class="col-12 p-3">
<ul class="list-group">
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">{{ 'Label'|trans }}</span>
{{ entity.label }}
</li>
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">{{ 'Locale'|trans }}</span>
{{ entity.locale }}
</li>
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">{{ 'Code'|trans }}</span>
{{ entity.code }}
<div class="row">
<div class="col-md-4">
<span class="font-weight-bold pb-2 d-block">{{ 'Label'|trans }}</span>
{{ entity.label }}
</div>
<div class="col-md-4">
<span class="font-weight-bold pb-2 d-block">{{ 'Locale'|trans }}</span>
{{ entity.locale }}
</div>
<div class="col-md-4">
<span class="font-weight-bold pb-2 d-block">{{ 'Code'|trans }}</span>
{{ entity.code }}
</div>
</div>
</li>
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">{{ 'Domain'|trans }}</span>
<div class="mb-3">
<span class="font-weight-bold pb-2 d-block">{{ 'Domain'|trans }}</span>
{{ entity.domain }}
</div>
<div>
{% set additionalDomains = entity.additionalDomains %}
{{ entity.domain }}
</li>
{% set additionalDomains = entity.additionalDomains %}
{% if additionalDomains|length %}
<li class="list-group-item">
<span class="font-weight-bold pb-2 d-block">{{ 'Additional domains'|trans }}</span>
{% for item in additionalDomains %}
@ -37,11 +38,65 @@
({{ 'Domain'|trans|lower }})
{% else %}
({{ 'Regular expression'|trans|lower }})
{% endif %}
</div>
{% endfor %}
</li>
{% endif %}
{% endif %}
</div>
{% else %}
-
{% endfor %}
</div>
</li>
</ul>
</div>
<div class="table-responsive">
<table class="table">
<thead class="thead-light">
<tr>
<th class="col-5">{{ 'Label'|trans }}</th>
<th class="col-5">{{ 'Section'|trans }}</th>
<th class="col-2 miw-100 text-right">{{ 'Actions'|trans }}</th>
</tr>
</thead>
<tbody>
{% for item in datas.settings %}
{% set edit = path('admin_navigation_setting_edit', {entity: item.id}) %}
<tr data-dblclick="{{ edit }}">
<td class="col-5">
<a href="#" data-modal="{{ edit }}" class="font-weight-bold text-body d-block">
{{ item.label|trans }}
</a>
</td>
<td class="col-5">
<span class="btn btn-light">{{ item.section|trans }}</span>
</td>
<td class="col-2 miw-100 text-right">
<span data-modal="{{ edit }}" class="btn btn-sm btn-primary mr-1">
<span data-modal="{{ edit }}" class="fa fa-edit"></span>
</span>
<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('admin_navigation_setting_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>
</td>
</tr>
{% else %}
<tr>
<td class="col-12 text-center p-4 text-black-50" colspan="3">
<div class="display-1">
<span class="fa fa-search"></span>
</div>
<div class="display-5 mt-3">
{{ 'No result'|trans }}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

View File

@ -0,0 +1,100 @@
<?php
namespace App\Core\Setting;
use App\Core\Entity\NavigationSetting;
use App\Core\Entity\Site\Navigation;
use App\Core\Factory\NavigationSettingFactory;
use App\Core\Manager\EntityManager;
use App\Core\Repository\NavigationSettingRepositoryQuery;
use App\Core\Repository\Site\NavigationRepositoryQuery;
/**
* class NavigationSettingManager.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class NavigationSettingManager
{
protected EntityManager $entityManager;
protected NavigationSettingRepositoryQuery $query;
protected NavigationRepositoryQuery $navigationQuery;
protected NavigationSettingFactory $factory;
public function __construct(
EntityManager $entityManager,
NavigationSettingRepositoryQuery $query,
NavigationRepositoryQuery $navigationQuery,
NavigationSettingFactory $factory
) {
$this->entityManager = $entityManager;
$this->query = $query;
$this->navigationQuery = $navigationQuery;
$this->factory = $factory;
}
public function init($navigation, string $code, string $section, string $label, $value = null)
{
$entity = $this->get($this->getNavigation($navigation), $code);
$isNew = null === $entity;
if ($isNew) {
$entity = $this->factory->create($navigation, $code);
$entity->setValue($value);
}
$entity
->setSection($section)
->setLabel($label)
;
if ($isNew) {
$this->entityManager->create($entity);
} else {
$this->entityManager->update($entity);
}
}
public function get($navigation, string $code): ?NavigationSetting
{
return $this->query->create()
->andWhere('.navigation = :navigation')
->andWhere('.code = :code')
->setParameter(':navigation', $this->getNavigation($navigation)->getId())
->setParameter(':code', $code)
->findOne()
;
}
public function set($navigation, string $code, $value): bool
{
$entity = $this->get($this->getNavigation($navigation), $code);
if (!$entity) {
return false;
}
$entity->setValue($value);
$this->entityManager->update($entity);
return true;
}
protected function getNavigation($navigation): Navigation
{
if ($navigation instanceof Navigation) {
return $navigation;
}
$entity = $this->navigationQuery->create()
->where('.code', $navigation)
->findOne()
;
if (!$entity) {
throw new \RuntimeException(sprintf('The navigation "%s" does not exist.', $navigation));
}
return $entity;
}
}

View File

@ -36,7 +36,6 @@ class SettingManager
}
$entity
->setCode($code)
->setSection($section)
->setLabel($label)
;

View File

@ -3,16 +3,19 @@
namespace App\Core\Twig\Extension;
use App\Core\Setting\SettingManager;
use App\Core\Setting\NavigationSettingManager;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class SettingExtension extends AbstractExtension
{
private SettingManager $manager;
private SettingManager $settingManager;
private NavigationSettingManager $navigationSettingManager;
public function __construct(SettingManager $manager)
public function __construct(SettingManager $settingManager, NavigationSettingManager $navigationSettingManager)
{
$this->manager = $manager;
$this->settingManager = $settingManager;
$this->navigationSettingManager = $navigationSettingManager;
}
/**
@ -22,12 +25,20 @@ class SettingExtension extends AbstractExtension
{
return [
new TwigFunction('setting', [$this, 'getSetting']),
new TwigFunction('navigation_setting', [$this, 'getNavigationSetting']),
];
}
public function getSetting(string $code)
{
$entity = $this->manager->get($code);
$entity = $this->settingManager->get($code);
return $entity ? $entity->getValue() : null;
}
public function getNavigationSetting($navigation, string $code)
{
$entity = $this->navigationSettingManager->get($navigation, $code);
return $entity ? $entity->getValue() : null;
}