crudification + corrections on thirdparty

This commit is contained in:
Julien Fastré 2021-10-04 18:25:49 +02:00
parent cc7e38194f
commit 05b9476a71
16 changed files with 313 additions and 212 deletions

View File

@ -209,22 +209,24 @@ class CRUDController extends AbstractController
* This method:
*
* 1. Launch `onPreIndex`
* x. check acl. If it does return a response instance, return it
* x. launch `onPostCheckACL`. If it does return a response instance, return it
* 1. count the items, using `countEntities`
* 2. build a paginator element from the the number of entities ;
* 3. Launch `onPreIndexQuery`. If it does return a response instance, return it
* 3. build a query, using `queryEntities`
* x. fetch the results, using `getQueryResult`
* x. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it
* 4. create default parameters:
* 2. check acl. If it does return a response instance, return it
* 3. launch `onPostCheckACL`. If it does return a response instance, return it
* 4. count the items, using `countEntities`
* 5. build a paginator element from the the number of entities ;
* 6. Launch `onPreIndexQuery`. If it does return a response instance, return it
* 7. fetch the results, using `getQueryResult`
*
* Internally, this build a query, using `queryEntities`
*
* 8. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it
* 9. create default parameters:
*
* The default parameters are:
*
* * entities: the list en entities ;
* * crud_name: the name of the crud ;
* * paginator: a paginator element ;
* 5. Launch rendering, the parameter is fetch using `getTemplateFor`
* 10. Launch rendering, the parameter is fetch using `getTemplateFor`
* The parameters may be personnalized using `generateTemplateParameter`.
*
* @param string $action
@ -259,16 +261,7 @@ class CRUDController extends AbstractController
return $response;
}
$query = $this->queryEntities($action, $request, $paginator);
$response = $this->onPostIndexBuildQuery($action, $request, $totalItems,
$paginator, $query);
if ($response instanceof Response) {
return $response;
}
$entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $query);
$entities = $this->getQueryResult($action, $request, $totalItems, $paginator);
$response = $this->onPostIndexFetchQuery($action, $request, $totalItems,
$paginator, $entities);
@ -393,11 +386,12 @@ class CRUDController extends AbstractController
* @param Request $request
* @param int $totalItems
* @param PaginatorInterface $paginator
* @param mixed $query
* @return mixed
*/
protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query)
protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator)
{
$query = $this->queryEntities($action, $request, $paginator);
return $query->getQuery()->getResult();
}

View File

@ -32,17 +32,20 @@
{% endif %}
<div class="crud_index__pagination">
{{ chill_pagination(paginator) }}
</div>
{% block pagination %}
<div class="crud_index__pagination">
{{ chill_pagination(paginator) }}
</div>
{% endblock %}
{% block list_actions %}
<ul class="record_actions sticky-form-buttons">
{% block add_new %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_' ~ crud_name ~ '_new') }}" class="btn btn-new">{{ ('crud.'~crud_name~'.index.add_new')|trans( {'%crud_name%': crud_name} ) }}</a>
</li>
{% endblock %}
{% block actions_before %}{% endblock %}
{% block add_new %}
<li>
<a href="{{ chill_path_add_return_path('chill_crud_' ~ crud_name ~ '_new') }}" class="btn btn-new">{{ ('crud.'~crud_name~'.index.add_new')|trans( {'%crud_name%': crud_name} ) }}</a>
</li>
{% endblock %}
</ul>
{% endblock list_actions %}
</div>

View File

@ -2,6 +2,11 @@
namespace Chill\ThirdPartyBundle\Controller;
use Chill\MainBundle\CRUD\Controller\AbstractCRUDController;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\ThirdPartyBundle\Repository\ThirdPartyACLAwareRepositoryInterface;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
@ -16,12 +21,7 @@ use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Security\Core\Role\Role;
use Chill\MainBundle\Pagination\PaginatorFactory;
/**
* Routes for operations on ThirdParties.
*
* @Route("/{_locale}/thirdparty/thirdparty")
*/
class ThirdPartyController extends Controller
final class ThirdPartyController extends CRUDController
{
/**
*
@ -41,37 +41,33 @@ class ThirdPartyController extends Controller
*/
protected $paginatorFactory;
protected ThirdPartyACLAwareRepositoryInterface $thirdPartyACLAwareRepository;
public function __construct(
AuthorizationHelper $authorizationHelper,
TranslatorInterface $translator,
PaginatorFactory $paginatorFactory
PaginatorFactory $paginatorFactory,
ThirdPartyACLAwareRepositoryInterface $thirdPartyACLAwareRepository
) {
$this->authorizationHelper = $authorizationHelper;
$this->translator = $translator;
$this->paginatorFactory = $paginatorFactory;
$this->thirdPartyACLAwareRepository = $thirdPartyACLAwareRepository;
}
/**
* @Route("/index", name="chill_3party_3party_index")
*/
public function indexAction()
protected function countEntities(string $action, Request $request): int
{
$this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW);
$repository = $this->getDoctrine()->getManager()
->getRepository(ThirdParty::class);
$nbThirdParties = $repository->count([]); //$repository->countByMemberOfCenters($centers);
$pagination = $this->paginatorFactory->create($nbThirdParties);
$thirdParties = $repository->findAll();
return $this->render('ChillThirdPartyBundle:ThirdParty:index.html.twig', array(
'third_parties' => $thirdParties,
'pagination' => $pagination
));
return $this->thirdPartyACLAwareRepository->countThirdParties(ThirdPartyVoter::SHOW);
}
protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator)
{
return $this->thirdPartyACLAwareRepository
->listThirdParties(ThirdPartyVoter::class, ['name' => 'ASC'], $paginator->getItemsPerPage(),
$paginator->getCurrentPageFirstItemNumber());
}
/**
* @Route("/new", name="chill_3party_3party_new")
*/

View File

@ -2,6 +2,9 @@
namespace Chill\ThirdPartyBundle\DependencyInjection;
use Chill\ThirdPartyBundle\Controller\ThirdPartyController;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Chill\ThirdPartyBundle\Form\ThirdPartyType;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
@ -37,6 +40,7 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte
$loader->load('services/menu.yaml');
$loader->load('services/fixtures.yaml');
$loader->load('services/serializer.yaml');
$loader->load('services/repository.yaml');
}
public function prepend(ContainerBuilder $container)
@ -54,6 +58,25 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte
'@ChillThirdPartyBundle/config/routes.yaml'
)
],
'cruds' => [
[
'class' => ThirdParty::class,
'controller' => ThirdPartyController::class,
'name' => '3party_3party',
'base_path' => '/3party/3party',
'form_class' => ThirdPartyType::class,
'actions' => [
'index' => [
'template' => '@ChillThirdParty/ThirdParty/index.html.twig',
'role' => ThirdPartyVoter::SHOW,
],
'new' => [
'role' => ThirdPartyVoter::CREATE,
]
]
]
],
'apis' => [
[
'class' => \Chill\ThirdPartyBundle\Entity\ThirdParty::class,

View File

@ -40,7 +40,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
* center.
*
* @ORM\Table(name="chill_3party.third_party")
* @ORM\Entity(repositoryClass="Chill\ThirdPartyBundle\Repository\ThirdPartyRepository")
* @ORM\Entity
* @DiscriminatorMap(typeProperty="type", mapping={
* "thirdparty"=ThirdParty::class
* })

View File

@ -60,7 +60,7 @@ class MenuBuilder implements LocalMenuBuilderInterface
->addChild(
$this->translator->trans('Third parties'),
[
'route' => 'chill_3party_3party_index',
'route' => 'chill_crud_3party_3party_index',
])
->setExtras([
'order' => 112

View File

@ -2,22 +2,52 @@
namespace Chill\ThirdPartyBundle\Repository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Security\Core\Security;
/**
* @Author Mathieu Jaumotte mathieu.jaumotte@champs-libres.coop
*/
class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepositoryInterface
final class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepositoryInterface
{
private Security $security;
private AuthorizationHelper $authorizationHelper;
private ThirdPartyRepository $thirdPartyRepository;
public function findByThirdparty(
ThirdParty $thirdparty,
string $role,
?array $orderBy = [],
int $limit = null,
int $offset = null
public function __construct(Security $security, AuthorizationHelper $authorizationHelper, ThirdPartyRepository $thirdPartyRepository)
{
$this->security = $security;
$this->authorizationHelper = $authorizationHelper;
$this->thirdPartyRepository = $thirdPartyRepository;
}
public function listThirdParties(
string $role,
?array $orderBy = [],
?int $limit = null,
?int $offset = null
): array {
$qb = $this->buildQuery($role);
// TODO: Implement findByThirdparty() method.
foreach ($orderBy as $sort => $direction) {
$qb->addOrderBy('tp.'.$sort, $direction);
}
$qb->setFirstResult($offset)
->setMaxResults($limit);
return $qb->getQuery()->getResult();
}
public function countThirdParties(
string $role
): int {
$qb = $this->buildQuery($role);
$qb->select('count(tp)');
return $qb->getQuery()->getSingleScalarResult();
}
public function buildQuery(): QueryBuilder {
return $this->thirdPartyRepository->createQueryBuilder('tp');
}
}

View File

@ -6,8 +6,16 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
interface ThirdPartyACLAwareRepositoryInterface
{
public function findByThirdparty(
ThirdParty $thirdparty,
public function countThirdParties(string $role): int;
/**
* @param string $role
* @param array|null $orderBy
* @param int|null $limit
* @param int|null $offset
* @return array|ThirdParty[]
*/
public function listThirdParties(
string $role,
?array $orderBy = [],
int $limit = null,

View File

@ -2,18 +2,21 @@
namespace Chill\ThirdPartyBundle\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\Persistence\ObjectRepository;
class ThirdPartyRepository extends ServiceEntityRepository
final class ThirdPartyRepository implements ObjectRepository
{
public function __construct(ManagerRegistry $registry)
private EntityRepository $repository;
public function __construct(EntityManagerInterface $em)
{
parent::__construct($registry, ThirdParty::class);
$this->repository = $em->getRepository(ThirdParty::class);
}
/**
@ -147,4 +150,45 @@ class ThirdPartyRepository extends ServiceEntityRepository
);
}
}
public function find($id): ?ThirdParty
{
return $this->repository->find($id);
}
/**
* @return array|ThirdParty[]
*/
public function findAll(): array
{
return $this->repository->findAll();
}
/**
* @param array $criteria
* @param array|null $orderBy
* @param null $limit
* @param null $offset
* @return array|ThirdParty[]
*/
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): array
{
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
public function findOneBy(array $criteria): ?ThirdParty
{
return $this->repository->findOneBy($criteria);
}
public function getClassName(): string
{
return ThirdParty::class;
}
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
{
return $this->repository->createQueryBuilder($alias, $indexBy);
}
}

View File

@ -2,108 +2,107 @@
{% block title 'List of third parties'|trans %}
{% set third_parties = entities %}
{% block content %}
<div class="thirdparty-list my-5">
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block index_header %}
<h1>{{ 'List of third parties'|trans }}</h1>
{% endblock %}
<h1>{{ 'List of third parties'|trans }}</h1>
{% block table_entities %}
<div class="thirdparty-list my-5">
{#
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
{% if third_parties|length == 0 %}
<p class="chill-no-data-statement">{{ 'No third parties'|trans }}</p>
{% else %}
{% if third_parties|length == 0 %}
<p class="chill-no-data-statement">{{ 'No third parties'|trans }}</p>
{% else %}
<nav class="filter-actions border border-secondary my-4 p-3">
<i>outils de filtrage</i>
</nav>
<nav class="filter-actions border border-secondary my-4 p-3">
<i>outils de filtrage</i>
</nav>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-10 col-xxl">
#}
<div class="row justify-content-center">
<div>
<label class="counter">
<span>{{ pagination.totalItems }}</span> {{ 'third parties'|trans }}
</label>
<label class="counter">
<span>{{ paginator.totalItems }}</span> {{ 'third parties'|trans }}
</label>
<table class="table table-bordered border-dark table-striped align-middle">
<thead>
<tr>
<th class="chill-pink" style="width: 35px;"></th>
<th class="chill-pink">{{ 'Name'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'Category'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'Address'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'thirdparty.UpdatedAt.short'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink"></th>
</tr>
</thead>
<tbody>
{% for tp in third_parties %}
<tr>
<th>{{ (tp.active ? '<i class="fa fa-check chill-green">' : '<i class="fa fa-times chill-red">')|raw }}</th>
<td>{{ tp.name }}</td>
{% set types = [] %}
{% for t in tp.types %}
{% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %}
{% endfor %}
<td>{{ types|join(', ') }}</td>
<td>
{{ tp.address|chill_entity_render_box({'multiline': false, 'with_valid_from': false}) }}
</td>
<td>
{% if tp.updatedAt != null %}
{{ tp.updatedAt|format_date('short') }}
{% else %}
{{ tp.createdAt|format_date('short') }}
{% endif %}
</td>
<td>
<ul class="record_actions">
{% if is_granted('CHILL_3PARTY_3PARTY_UPDATE', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_3party_3party_update', { 'thirdparty_id': tp.id }) }}" class="btn btn-sm btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_3PARTY_3PARTY_SHOW', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_3party_3party_show', { 'thirdparty_id': tp.id }) }}" class="btn btn-sm btn-show"></a>
</li>
{% endif %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if third_parties|length < pagination.getTotalItems %}
{{ chill_pagination(pagination, 'long') }}
{% endif %}
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
{{ chill_items_per_page(pagination) }}
</li>
{% if is_granted('CHILL_3PARTY_3PARTY_CREATE') %}
<li>
<a href="{{ chill_path_add_return_path('chill_3party_3party_new') }}" class="btn btn-create">
{{ "New third party"|trans }}
</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
<table class="table table-bordered border-dark table-striped align-middle">
<thead>
<tr>
<th class="chill-pink" style="width: 35px;"></th>
<th class="chill-pink">{{ 'Name'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'Category'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'Address'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink">{{ 'thirdparty.UpdatedAt.short'|trans }}
<i class="fa fa-fw fa-sort"></i>
</th>
<th class="chill-pink"></th>
</tr>
</thead>
<tbody>
{% for tp in third_parties %}
<tr>
<th>{{ (tp.active ? '<i class="fa fa-check chill-green">' : '<i class="fa fa-times chill-red">')|raw }}</th>
<td>{{ tp.name }}</td>
{% set types = [] %}
{% for t in tp.types %}
{% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %}
{% endfor %}
<td>{{ types|join(', ') }}</td>
<td>
{{ tp.address|chill_entity_render_box({'multiline': false, 'with_valid_from': false}) }}
</td>
<td>
{% if tp.updatedAt != null %}
{{ tp.updatedAt|format_date('short') }}
{% else %}
{{ tp.createdAt|format_date('short') }}
{% endif %}
</td>
<td>
<ul class="record_actions">
{% if is_granted('CHILL_3PARTY_3PARTY_UPDATE', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_3party_3party_update', { 'thirdparty_id': tp.id }) }}" class="btn btn-sm btn-update"></a>
</li>
{% endif %}
{% if is_granted('CHILL_3PARTY_3PARTY_SHOW', tp) %}
<li>
<a href="{{ chill_path_add_return_path('chill_3party_3party_show', { 'thirdparty_id': tp.id }) }}" class="btn btn-sm btn-show"></a>
</li>
{% endif %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}
{% block actions_before %}
<li class="cancel">
{{ chill_items_per_page(paginator) }}
</li>
{% endblock %}
{% endembed %}
{% endblock %}
{% block css %}
{{ encore_entry_link_tags('page_3party_3party_index') }}
{% endblock %}

View File

@ -1,9 +1,12 @@
module.exports = function(encore, entries)
{
entries.push(__dirname + '/Resources/public/chill/index.js');
// Aliases are used when webpack is trying to resolve modules path
encore.addAliases({
ChillThirdPartyAssets: __dirname + '/Resources/public'
});
encore.addEntry(
'page_3party_3party_index',
__dirname + '/Resources/public/page/index/index.js'
);
};

View File

@ -6,8 +6,3 @@ services:
tags:
- { name: 'serializer.normalizer', priority: 64 }
Chill\ThirdPartyBundle\Repository\:
autowire: true
resource: '../Repository/'
tags:
- { name: 'doctrine.repository_service' }

View File

@ -1,7 +1,5 @@
services:
Chill\ThirdPartyBundle\Controller\ThirdPartyController:
arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
$translator: '@Symfony\Component\Translation\TranslatorInterface'
$paginatorFactory: '@Chill\MainBundle\Pagination\PaginatorFactory'
tags: ['controller.service_arguments']
Chill\ThirdPartyBundle\Controller\:
resource: './../Controller'
autowire: true
autoconfigure: true

View File

@ -0,0 +1,8 @@
---
services:
Chill\ThirdPartyBundle\Repository\:
autowire: true
autoconfigure: true
resource: '../Repository/'
Chill\ThirdPartyBundle\Repository\ThirdPartyACLAwareRepositoryInterface: '@Chill\ThirdPartyBundle\Repository\ThirdPartyACLAwareRepository'