From 4d71a1c630102a36d4915f48d4fe55b0d148ad17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 8 Oct 2021 16:50:31 +0200 Subject: [PATCH] add possibility to generate filter/order elements, with only search box for now --- .../Controller/AsideActivityController.php | 7 +- .../CRUD/Controller/CRUDController.php | 34 ++++++--- .../Form/Type/Listing/FilterOrderType.php | 55 ++++++++++++++ .../Resources/views/CRUD/_index.html.twig | 6 ++ .../views/FilterOrder/base.html.twig | 12 +++ .../Templating/Listing/FilterOrderHelper.php | 60 +++++++++++++++ .../Listing/FilterOrderHelperBuilder.php | 40 ++++++++++ .../Listing/FilterOrderHelperFactory.php | 26 +++++++ .../FilterOrderHelperFactoryInterface.php | 8 ++ .../Templating/Listing/Templating.php | 34 +++++++++ .../config/services/templating.yaml | 10 ++- .../Controller/ThirdPartyController.php | 22 +++++- .../ThirdPartyACLAwareRepository.php | 20 +++-- .../ThirdPartyACLAwareRepositoryInterface.php | 7 +- .../views/ThirdParty/index.html.twig | 73 +++---------------- 15 files changed, 325 insertions(+), 89 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php create mode 100644 src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig create mode 100644 src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php create mode 100644 src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php create mode 100644 src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php create mode 100644 src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactoryInterface.php create mode 100644 src/Bundle/ChillMainBundle/Templating/Listing/Templating.php diff --git a/src/Bundle/ChillAsideActivityBundle/src/Controller/AsideActivityController.php b/src/Bundle/ChillAsideActivityBundle/src/Controller/AsideActivityController.php index a0362ec12..3e3b38033 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Controller/AsideActivityController.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Controller/AsideActivityController.php @@ -7,6 +7,7 @@ namespace Chill\AsideActivityBundle\Controller; use Chill\AsideActivityBundle\Entity\AsideActivity; use Chill\AsideActivityBundle\Repository\AsideActivityCategoryRepository; use Chill\MainBundle\CRUD\Controller\CRUDController; +use Chill\MainBundle\Templating\Listing\FilterOrderHelper; use Doctrine\ORM\QueryBuilder; use Symfony\Component\HttpFoundation\Request; use Chill\MainBundle\Pagination\PaginatorInterface; @@ -22,9 +23,9 @@ final class AsideActivityController extends CRUDController $this->categoryRepository = $categoryRepository; } - protected function buildQueryEntities(string $action, Request $request) + protected function buildQueryEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null) { - $qb = parent::buildQueryEntities($action, $request); + $qb = parent::buildQueryEntities($action, $request, $filterOrder); if ('index' === $action) { $qb->where($qb->expr()->eq('e.agent', ':user')); @@ -53,7 +54,7 @@ final class AsideActivityController extends CRUDController $asideActivity = new AsideActivity(); $duration = $request->query->get('duration', '300'); - $duration = \DateTime::createFromFormat('U', $duration); + $duration = \DateTime::createFromFormat('U', $duration); $asideActivity->setDuration($duration); $categoryId = $request->query->get('type', 7); diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php index 6a377f361..9c657ae46 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php @@ -20,6 +20,8 @@ namespace Chill\MainBundle\CRUD\Controller; +use Chill\MainBundle\Templating\Listing\FilterOrderHelper; +use Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; @@ -251,7 +253,8 @@ class CRUDController extends AbstractController return $response; } - $totalItems = $this->countEntities($action, $request); + $filterOrder = $this->buildFilterOrderHelper($action, $request); + $totalItems = $this->countEntities($action, $request, $filterOrder); $paginator = $this->getPaginatorFactory()->create($totalItems); $response = $this->onPreIndexBuildQuery($action, $request, $totalItems, @@ -261,7 +264,7 @@ class CRUDController extends AbstractController return $response; } - $entities = $this->getQueryResult($action, $request, $totalItems, $paginator); + $entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $filterOrder); $response = $this->onPostIndexFetchQuery($action, $request, $totalItems, $paginator, $entities); @@ -273,7 +276,8 @@ class CRUDController extends AbstractController $defaultTemplateParameters = [ 'entities' => $entities, 'crud_name' => $this->getCrudName(), - 'paginator' => $paginator + 'paginator' => $paginator, + 'filter_order' => $filterOrder ]; return $this->render( @@ -282,6 +286,11 @@ class CRUDController extends AbstractController ); } + protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper + { + return null; + } + /** * @param string $action * @param Request $request @@ -354,9 +363,9 @@ class CRUDController extends AbstractController * @param PaginatorInterface $paginator * @return type */ - protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator) + protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator, ?FilterOrderHelper $filterOrder = null) { - $query = $this->buildQueryEntities($action, $request) + $query = $this->buildQueryEntities($action, $request, $filterOrder) ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) ->setMaxResults($paginator->getItemsPerPage()); @@ -388,9 +397,10 @@ class CRUDController extends AbstractController * @param PaginatorInterface $paginator * @return mixed */ - protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator) + protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, + ?FilterOrderHelper $filterOrder = null) { - $query = $this->queryEntities($action, $request, $paginator); + $query = $this->queryEntities($action, $request, $paginator, $filterOrder); return $query->getQuery()->getResult(); } @@ -402,9 +412,9 @@ class CRUDController extends AbstractController * @param Request $request * @return int */ - protected function countEntities(string $action, Request $request): int + protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int { - return $this->buildQueryEntities($action, $request) + return $this->buildQueryEntities($action, $request, $filterOrder) ->select('COUNT(e)') ->getQuery() ->getSingleScalarResult() @@ -1177,6 +1187,11 @@ class CRUDController extends AbstractController return $this->get(Resolver::class); } + protected function getFilterOrderHelperFactory(): FilterOrderHelperFactoryInterface + { + return $this->get(FilterOrderHelperFactoryInterface::class); + } + /** * @return array */ @@ -1191,6 +1206,7 @@ class CRUDController extends AbstractController EventDispatcherInterface::class => EventDispatcherInterface::class, Resolver::class => Resolver::class, SerializerInterface::class => SerializerInterface::class, + FilterOrderHelperFactoryInterface::class => FilterOrderHelperFactoryInterface::class, ] ); } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php new file mode 100644 index 000000000..1068301b0 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/Type/Listing/FilterOrderType.php @@ -0,0 +1,55 @@ +requestStack = $requestStack; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + /** @var FilterOrderHelper $helper */ + $helper = $options['helper']; + + if ($helper->hasSearchBox()) { + $builder->add('q', SearchType::class, [ + 'label' => false, + 'required' => false + ]); + } + + foreach ($this->requestStack->getCurrentRequest()->query->getIterator() as $key => $value) { + switch($key) { + case 'q': + continue; + case 'page': + $builder->add($key, HiddenType::class, [ + 'data' => 1 + ]); + break; + default: + $builder->add($key, HiddenType::class, [ + 'data' => $value + ]); + break; + } + } + } + + public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver) + { + $resolver->setRequired('helper') + ->setAllowedTypes('helper', FilterOrderHelper::class); + } +} diff --git a/src/Bundle/ChillMainBundle/Resources/views/CRUD/_index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/CRUD/_index.html.twig index 1fb35dd55..15774bdf6 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/CRUD/_index.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/CRUD/_index.html.twig @@ -4,6 +4,12 @@

{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}

{% endblock index_header %} +{% block filter_order %} + {% if filter_order is not null %} + {{ filter_order|chill_render_filter_order_helper }} + {% endif %} +{% endblock %} + {% if entities|length == 0 %} {% block no_existing_entities %}

{{ no_existing_entities_sentences|default('No entities')|trans }}

diff --git a/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig new file mode 100644 index 000000000..074f3bb94 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Resources/views/FilterOrder/base.html.twig @@ -0,0 +1,12 @@ +{{ form_start(form) }} +
+
+
+
+ {{ form_widget(form.q)}} + +
+
+
+
+{{ form_end(form) }} diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php new file mode 100644 index 000000000..0b9eb60bb --- /dev/null +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -0,0 +1,60 @@ +formFactory = $formFactory; + $this->requestStack = $requestStack; + } + + public function setSearchBox($searchBoxFields = null): self + { + $this->searchBoxFields = $searchBoxFields; + + return $this; + } + + public function hasSearchBox(): bool + { + return $this->searchBoxFields !== null; + } + + private function getFormData(): array + { + return [ + 'q' => $this->getQueryString() + ]; + } + + public function getQueryString(): ?string + { + $q = $this->requestStack->getCurrentRequest() + ->query->get('q', null); + + return empty($q) ? NULL : $q; + } + + public function buildForm($name = null, string $type = FilterOrderType::class, array $options = []): FormInterface + { + return $this->formFactory + ->createNamed($name, $type, $this->getFormData(), \array_merge([ + 'helper' => $this, + 'method' => 'GET', + 'csrf_protection' => false, + ], $options)); + } +} diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php new file mode 100644 index 000000000..e1df09827 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperBuilder.php @@ -0,0 +1,40 @@ +formFactory = $formFactory; + $this->requestStack = $requestStack; + } + + public function addSearchBox(array $fields, ?array $options = []): self + { + $this->searchBoxFields = $fields; + + return $this; + } + + public function build(): FilterOrderHelper + { + $helper = new FilterOrderHelper( + $this->formFactory, + $this->requestStack + ); + + $helper->setSearchBox($this->searchBoxFields); + + return $helper; + } +} diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php new file mode 100644 index 000000000..1b1c4c983 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactory.php @@ -0,0 +1,26 @@ +formFactory = $formFactory; + $this->requestStack = $requestStack; + } + + public function create(string $context, ?array $options = []): FilterOrderHelperBuilder + { + return new FilterOrderHelperBuilder($this->formFactory, $this->requestStack); + } +} diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactoryInterface.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactoryInterface.php new file mode 100644 index 000000000..a222adf7a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelperFactoryInterface.php @@ -0,0 +1,8 @@ + true, 'is_safe' => ['html'], + ]) + ]; + } + + public function renderFilterOrderHelper( + Environment $environment, + FilterOrderHelper $helper, + ?string $template = '@ChillMain/FilterOrder/base.html.twig', + ?array $options = [] + ) { + return $environment->render($template, [ + 'helper' => $helper, + 'form' => $helper->buildForm()->createView(), + 'options' => $options + ]); + } + +} diff --git a/src/Bundle/ChillMainBundle/config/services/templating.yaml b/src/Bundle/ChillMainBundle/config/services/templating.yaml index cd35a6466..e264f3a99 100644 --- a/src/Bundle/ChillMainBundle/config/services/templating.yaml +++ b/src/Bundle/ChillMainBundle/config/services/templating.yaml @@ -36,7 +36,7 @@ services: autowire: true tags: - { name: 'chill.render_entity' } - + Chill\MainBundle\Templating\ChillMarkdownRenderExtension: tags: - { name: twig.extension } @@ -46,4 +46,10 @@ services: - '@Symfony\Component\Templating\EngineInterface' tags: - { name: 'chill.render_entity' } - + + Chill\MainBundle\Templating\Listing\: + resource: './../../Templating/Listing' + autoconfigure: true + autowire: true + + Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface: '@Chill\MainBundle\Templating\Listing\FilterOrderHelperFactory' diff --git a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php index 8078f720a..42427544c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php +++ b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php @@ -5,6 +5,7 @@ namespace Chill\ThirdPartyBundle\Controller; use Chill\MainBundle\CRUD\Controller\AbstractCRUDController; use Chill\MainBundle\CRUD\Controller\CRUDController; use Chill\MainBundle\Pagination\PaginatorInterface; +use Chill\MainBundle\Templating\Listing\FilterOrderHelper; use Chill\ThirdPartyBundle\Repository\ThirdPartyACLAwareRepositoryInterface; use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -56,15 +57,20 @@ final class ThirdPartyController extends CRUDController $this->thirdPartyACLAwareRepository = $thirdPartyACLAwareRepository; } - protected function countEntities(string $action, Request $request): int + protected function countEntities(string $action, Request $request, ?FilterOrderHelper $filterOrder = null): int { - return $this->thirdPartyACLAwareRepository->countThirdParties(ThirdPartyVoter::SHOW); + if (NULL === $filterOrder){ + throw new \LogicException('filterOrder should not be null'); + } + + return $this->thirdPartyACLAwareRepository->countThirdParties(ThirdPartyVoter::SHOW, + $filterOrder->getQueryString()); } - protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator) + protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, ?FilterOrderHelper $filterOrder = null) { return $this->thirdPartyACLAwareRepository - ->listThirdParties(ThirdPartyVoter::class, ['name' => 'ASC'], $paginator->getItemsPerPage(), + ->listThirdParties(ThirdPartyVoter::SHOW, $filterOrder->getQueryString(), ['name' => 'ASC'], $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); } @@ -78,4 +84,12 @@ final class ThirdPartyController extends CRUDController return null; } + + protected function buildFilterOrderHelper(string $action, Request $request): ?FilterOrderHelper + { + return $this->getFilterOrderHelperFactory() + ->create(self::class) + ->addSearchBox(['name', 'company_name', 'acronym']) + ->build(); + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php index 46f52d8b6..ab535e60e 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php @@ -22,11 +22,12 @@ final class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepository public function listThirdParties( string $role, + ?string $filterString, ?array $orderBy = [], ?int $limit = null, ?int $offset = null ): array { - $qb = $this->buildQuery($role); + $qb = $this->buildQuery($filterString); foreach ($orderBy as $sort => $direction) { $qb->addOrderBy('tp.'.$sort, $direction); @@ -39,15 +40,24 @@ final class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepository } public function countThirdParties( - string $role + string $role, + ?string $filterString ): int { - $qb = $this->buildQuery($role); + $qb = $this->buildQuery($filterString); $qb->select('count(tp)'); return $qb->getQuery()->getSingleScalarResult(); } - public function buildQuery(): QueryBuilder { - return $this->thirdPartyRepository->createQueryBuilder('tp'); + public function buildQuery(?string $filterString = null): QueryBuilder + { + $qb = $this->thirdPartyRepository->createQueryBuilder('tp'); + + if (NULL !== $filterString) { + $qb->andWhere($qb->expr()->like('tp.canonicalized', 'LOWER(UNACCENT(:filterString))')) + ->setParameter('filterString', '%'.$filterString.'%'); + } + + return $qb; } } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php index 23c92e7f7..459ac896a 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepositoryInterface.php @@ -6,7 +6,7 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty; interface ThirdPartyACLAwareRepositoryInterface { - public function countThirdParties(string $role): int; + public function countThirdParties(string $role, ?string $filterString): int; /** * @param string $role @@ -17,8 +17,9 @@ interface ThirdPartyACLAwareRepositoryInterface */ public function listThirdParties( string $role, + ?string $filterString, ?array $orderBy = [], - int $limit = null, - int $offset = null + ?int $limit = 0, + ?int $offset = 50 ): array; } diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/index.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/index.html.twig index 25c1779af..a3d20f04f 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/index.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/index.html.twig @@ -12,21 +12,6 @@ {% block table_entities %}
- {# -
-
- - {% if third_parties|length == 0 %} -

{{ 'No third parties'|trans }}

- {% else %} - - - -
-
- #}
@@ -34,49 +19,11 @@ {{ paginator.totalItems }} {{ 'third parties'|trans }} - - - - - - - - - - - - - {% for tp in third_parties %} - - - - {% set types = [] %} - {% for t in tp.types %} - {% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %} - {% endfor %} - - - - - - {% endfor %} - -
{{ 'Name'|trans }} - - {{ 'Category'|trans }} - - {{ 'Address'|trans }} - - {{ 'thirdparty.UpdatedAt.short'|trans }} - -
{{ (tp.active ? '' : '')|raw }} - {{ tp.name }} - {% if tp.isChild %}{{ 'Contact'|trans }}{% endif %} - {{ types|join(', ') }} - {{ tp.address|chill_entity_render_box({'multiline': false, 'with_valid_from': false}) }} - - {% if tp.updatedAt != null %} - {{ tp.updatedAt|format_date('short') }} - {% else %} - {{ tp.createdAt|format_date('short') }} - {% endif %} - +
+ {% for tp in third_parties %} +
+ {{ tp|chill_entity_render_box({'render': 'bloc', 'addLink': false}) }} +
    {% if is_granted('CHILL_3PARTY_3PARTY_UPDATE', tp) %}
  • @@ -91,11 +38,11 @@
  • {% endif %}
-
+ +
+
+ {% endfor %} +