Render for generic doc

This commit is contained in:
Julien Fastré 2023-05-24 21:57:20 +02:00
parent 8dbe2d6ec2
commit e550817ded
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
14 changed files with 299 additions and 66 deletions

View File

@ -11,7 +11,8 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle;
use Chill\DocStoreBundle\GenericDoc\ProviderForAccompanyingPeriodInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
@ -19,7 +20,9 @@ class ChillDocStoreBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
$container->registerForAutoconfiguration(ProviderForAccompanyingPeriodInterface::class)
$container->registerForAutoconfiguration(GenericDocForAccompanyingPeriodProviderInterface::class)
->addTag('chill_doc_store.generic_doc_accompanying_period_provider');
$container->registerForAutoconfiguration(GenericDocRendererInterface::class)
->addTag('chill_doc_store.generic_doc_renderer');
}
}

View File

@ -13,17 +13,22 @@ namespace Chill\DocStoreBundle\Controller;
use Chill\DocStoreBundle\GenericDoc\Manager;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Bundle\TwigBundle\TwigEngine;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Templating\EngineInterface;
final readonly class GenericDocForAccompanyingPeriodController
{
public function __construct(
private Security $security,
private Manager $manager
private Manager $manager,
private PaginatorFactory $paginator,
private EngineInterface $twig,
) {
}
@ -41,12 +46,21 @@ final readonly class GenericDocForAccompanyingPeriodController
}
$nb = $this->manager->countDocForAccompanyingPeriod($accompanyingPeriod);
$paginator = $this->paginator->create($nb);
$documents = $this->manager->findDocForAccompanyingPeriod(
$accompanyingPeriod,
$paginator->getCurrentPageFirstItemNumber(),
$paginator->getItemsPerPage()
);
foreach ($this->manager->findDocForAccompanyingPeriod($accompanyingPeriod) as $dto) {
dump($dto);
}
return new Response($nb);
return new Response($this->twig->render(
'@ChillDocStore/GenericDoc/accompanying_period_list.html.twig',
[
'accompanyingCourse' => $accompanyingPeriod,
'pagination' => $paginator,
'documents' => iterator_to_array($documents),
]
));
}
}

View File

@ -11,12 +11,16 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\GenericDoc;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
class GenericDocDTO
{
public function __construct(
public readonly string $key,
public readonly array $identifiers,
public readonly \DateTimeImmutable $docDate
public readonly \DateTimeImmutable $docDate,
public AccompanyingPeriod|Person $linked,
) {
}
}

View File

@ -13,7 +13,7 @@ namespace Chill\DocStoreBundle\GenericDoc;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
interface ProviderForAccompanyingPeriodInterface
interface GenericDocForAccompanyingPeriodProviderInterface
{
public function buildFetchQueryForAccompanyingPeriod(
AccompanyingPeriod $accompanyingPeriod,

View File

@ -23,7 +23,7 @@ class Manager
public function __construct(
/**
* @var iterable<ProviderForAccompanyingPeriodInterface>
* @var iterable<GenericDocForAccompanyingPeriodProviderInterface>
*/
private readonly iterable $providersForAccompanyingPeriod,
private readonly Connection $connection,
@ -81,7 +81,8 @@ class Manager
yield new GenericDocDTO(
$row['key'],
json_decode($row['identifiers'], true, JSON_THROW_ON_ERROR),
new \DateTimeImmutable($row['doc_date'])
new \DateTimeImmutable($row['doc_date']),
$accompanyingPeriod,
);
}
}

View File

@ -14,15 +14,17 @@ namespace Chill\DocStoreBundle\GenericDoc\Providers;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
use Chill\DocStoreBundle\GenericDoc\ProviderForAccompanyingPeriodInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Security;
final readonly class AccompanyingCourseDocumentProvider implements ProviderForAccompanyingPeriodInterface
final readonly class AccompanyingProviderCourseDocumentGenericDoc implements GenericDocForAccompanyingPeriodProviderInterface
{
public const KEY = 'accompanying_course_document';
public function __construct(
private Security $security,
private EntityManagerInterface $entityManager,
@ -34,7 +36,7 @@ final readonly class AccompanyingCourseDocumentProvider implements ProviderForAc
$classMetadata = $this->entityManager->getClassMetadata(AccompanyingCourseDocument::class);
$query = new FetchQuery(
'accompanying_course_document',
self::KEY,
sprintf('jsonb_build_object(\'id\', %s)', $classMetadata->getIdentifierColumnNames()[0]),
sprintf($classMetadata->getColumnName('date')),
$classMetadata->getSchemaName() . '.' . $classMetadata->getTableName()

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\GenericDoc\Renderer;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface;
use Chill\DocStoreBundle\GenericDoc\Providers\AccompanyingProviderCourseDocumentGenericDoc;
use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
final readonly class AccompanyingCourseDocumentGenericDocRenderer implements GenericDocRendererInterface
{
public function __construct(
private AccompanyingCourseDocumentRepository $accompanyingCourseDocumentRepository,
) {
}
public function supports(GenericDocDTO $genericDocDTO, $options = []): bool
{
return $genericDocDTO->key === AccompanyingProviderCourseDocumentGenericDoc::KEY;
}
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string
{
return '@ChillDocStore/List/list_item.html.twig';
}
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array
{
return [
'document' => $this->accompanyingCourseDocumentRepository->find($genericDocDTO->identifiers['id']),
'accompanyingCourse' => $genericDocDTO->linked,
'options' => $options,
];
}
}

View File

@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\GenericDoc\Twig;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
final class GenericDocExtension extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('chill_generic_doc_render', [GenericDocExtensionRuntime::class, 'renderGenericDoc'], [
'needs_environment' => true,
'is_safe' => ['html'],
])
];
}
}

View File

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\GenericDoc\Twig;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Extension\RuntimeExtensionInterface;
final readonly class GenericDocExtensionRuntime implements RuntimeExtensionInterface
{
public function __construct(
/**
* @var list<GenericDocRendererInterface>
*/
private iterable $renderers,
) {
}
/**
* @throws RuntimeError
* @throws SyntaxError
* @throws LoaderError
*/
public function renderGenericDoc(Environment $twig, GenericDocDTO $genericDocDTO, array $options = []): string
{
foreach ($this->renderers as $renderer) {
if ($renderer->supports($genericDocDTO)) {
return $twig->render(
$renderer->getTemplate($genericDocDTO, $options),
$renderer->getTemplateData($genericDocDTO, $options),
);
}
}
throw new \LogicException("no renderer found");
}
}

View File

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\DocStoreBundle\GenericDoc\Twig;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
interface GenericDocRendererInterface
{
public function supports(GenericDocDTO $genericDocDTO, $options = []): bool;
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string;
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array;
}

View File

@ -0,0 +1,48 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = '' %}
{% block title %}
{{ 'Documents' }}
{% endblock %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_entity_workflow_pick') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_entity_workflow_pick') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock %}
{% block content %}
<div class="document-list">
<h1>{{ 'Documents' }}</h1>
{% if documents|length == 0 %}
<p class="chill-no-data-statement">{{ 'No documents'|trans }}</p>
{% else %}
<div class="flex-table chill-task-list">
{% for document in documents %}
{{ document|chill_generic_doc_render }}
{% endfor %}
</div>
{% endif %}
{{ chill_pagination(pagination) }}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %}
<ul class="record_actions sticky-form-buttons">
<li class="create">
<a href="{{ path('accompanying_course_document_new', {'course': accompanyingCourse.id}) }}" class="btn btn-create">
{{ 'Create'|trans }}
</a>
</li>
</ul>
{% endif %}
</div>
{% endblock %}

View File

@ -15,7 +15,7 @@ use Chill\DocStoreBundle\GenericDoc\FetchQuery;
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Chill\DocStoreBundle\GenericDoc\Manager;
use Chill\DocStoreBundle\GenericDoc\ProviderForAccompanyingPeriodInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
@ -52,7 +52,7 @@ class ManagerTest extends KernelTestCase
}
$manager = new Manager(
[new SimpleProvider()],
[new SimpleGenericDocProvider()],
$this->connection,
);
@ -72,7 +72,7 @@ class ManagerTest extends KernelTestCase
}
$manager = new Manager(
[new SimpleProvider()],
[new SimpleGenericDocProvider()],
$this->connection,
);
@ -82,7 +82,7 @@ class ManagerTest extends KernelTestCase
}
}
final readonly class SimpleProvider implements ProviderForAccompanyingPeriodInterface
final readonly class SimpleGenericDocProvider implements GenericDocForAccompanyingPeriodProviderInterface
{
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
{

View File

@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Tests\GenericDoc\Providers;
use Chill\DocStoreBundle\GenericDoc\FetchQueryToSqlBuilder;
use Chill\DocStoreBundle\GenericDoc\Providers\AccompanyingCourseDocumentProvider;
use Chill\DocStoreBundle\GenericDoc\Providers\AccompanyingProviderCourseDocumentGenericDoc;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\DBAL\Types\Types;
@ -54,7 +54,7 @@ class AccompanyingCourseDocumentProviderTest extends KernelTestCase
$security->isGranted(AccompanyingCourseDocumentVoter::SEE, $period)
->willReturn(true);
$provider = new AccompanyingCourseDocumentProvider(
$provider = new AccompanyingProviderCourseDocumentGenericDoc(
$security->reveal(),
$this->entityManager
);

View File

@ -2,56 +2,71 @@ parameters:
# cl_chill_person.example.class: Chill\PersonBundle\Example
services:
Chill\DocStoreBundle\Repository\:
autowire: true
autoconfigure: true
resource: "../Repository/"
Chill\DocStoreBundle\Repository\:
autowire: true
autoconfigure: true
resource: "../Repository/"
Chill\DocStoreBundle\Form\DocumentCategoryType:
class: Chill\DocStoreBundle\Form\DocumentCategoryType
arguments: ["%kernel.bundles%"]
tags:
- { name: form.type }
Chill\DocStoreBundle\Form\DocumentCategoryType:
class: Chill\DocStoreBundle\Form\DocumentCategoryType
arguments: [ "%kernel.bundles%" ]
tags:
- { name: form.type }
Chill\DocStoreBundle\Form\PersonDocumentType:
class: Chill\DocStoreBundle\Form\PersonDocumentType
autowire: true
autoconfigure: true
# arguments:
# - "@chill.main.helper.translatable_string"
tags:
- { name: form.type, alias: chill_docstorebundle_form_document }
Chill\DocStoreBundle\Form\PersonDocumentType:
class: Chill\DocStoreBundle\Form\PersonDocumentType
autowire: true
autoconfigure: true
# arguments:
# - "@chill.main.helper.translatable_string"
tags:
- { name: form.type, alias: chill_docstorebundle_form_document }
Chill\DocStoreBundle\Security\Authorization\:
resource: "./../Security/Authorization"
autowire: true
autoconfigure: true
tags:
- { name: chill.role }
Chill\DocStoreBundle\Security\Authorization\:
resource: "./../Security/Authorization"
autowire: true
autoconfigure: true
tags:
- { name: chill.role }
Chill\DocStoreBundle\Workflow\:
resource: './../Workflow/'
autoconfigure: true
autowire: true
Chill\DocStoreBundle\Workflow\:
resource: './../Workflow/'
autoconfigure: true
autowire: true
Chill\DocStoreBundle\Serializer\Normalizer\:
autowire: true
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: 16 }
Chill\DocStoreBundle\Serializer\Normalizer\:
autowire: true
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: 16 }
Chill\DocStoreBundle\Service\:
autowire: true
autoconfigure: true
resource: '../Service/'
Chill\DocStoreBundle\Service\:
autowire: true
autoconfigure: true
resource: '../Service/'
Chill\DocStoreBundle\GenericDoc\Manager:
autowire: true
autoconfigure: true
arguments:
$providersForAccompanyingPeriod: !tagged_iterator chill_doc_store.generic_doc_accompanying_period_provider
Chill\DocStoreBundle\GenericDoc\Manager:
autowire: true
autoconfigure: true
arguments:
$providersForAccompanyingPeriod: !tagged_iterator chill_doc_store.generic_doc_accompanying_period_provider
Chill\DocStoreBundle\GenericDoc\Providers\:
autowire: true
autoconfigure: true
resource: '../GenericDoc/Providers/'
Chill\DocStoreBundle\GenericDoc\Twig\GenericDocExtension:
autoconfigure: true
autowire: true
Chill\DocStoreBundle\GenericDoc\Twig\GenericDocExtensionRuntime:
autoconfigure: true
autowire: true
arguments:
$renderers: !tagged_iterator chill_doc_store.generic_doc_renderer
Chill\DocStoreBundle\GenericDoc\Providers\:
autowire: true
autoconfigure: true
resource: '../GenericDoc/Providers/'
Chill\DocStoreBundle\GenericDoc\Renderer\:
autowire: true
autoconfigure: true
resource: '../GenericDoc/Renderer/'