mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
461 lines
18 KiB
PHP
461 lines
18 KiB
PHP
<?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 Service\DocGenerator;
|
|
|
|
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
|
|
use Chill\DocGeneratorBundle\Service\Context\BaseContextData;
|
|
use Chill\DocStoreBundle\Entity\DocumentCategory;
|
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
|
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
|
|
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
|
|
use Chill\MainBundle\Entity\Address;
|
|
use Chill\MainBundle\Entity\Center;
|
|
use Chill\MainBundle\Entity\PostalCode;
|
|
use Chill\MainBundle\Entity\Scope;
|
|
use Chill\MainBundle\Entity\User;
|
|
use Chill\MainBundle\Form\Type\ScopePickerType;
|
|
use Chill\MainBundle\Repository\ScopeRepositoryInterface;
|
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
use Chill\PersonBundle\Entity\Person;
|
|
use Chill\PersonBundle\Repository\ResidentialAddressRepository;
|
|
use Chill\PersonBundle\Service\DocGenerator\AccompanyingPeriodContext;
|
|
use Chill\PersonBundle\Service\DocGenerator\PersonContext;
|
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
|
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
|
|
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Prophecy\Argument;
|
|
use Prophecy\Exception\Prediction\FailedPredictionException;
|
|
use Prophecy\PhpUnit\ProphecyTrait;
|
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|
use Symfony\Component\Form\FormBuilderInterface;
|
|
use Symfony\Component\Security\Core\Security;
|
|
use Symfony\Component\Security\Core\User\UserInterface;
|
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
use function count;
|
|
|
|
/**
|
|
* @internal
|
|
* @coversNothing
|
|
*/
|
|
final class PersonContextTest extends KernelTestCase
|
|
{
|
|
use ProphecyTrait;
|
|
|
|
/**
|
|
* This test run the methods executed when a document is generated:
|
|
*
|
|
* - normalized data from the form in a way that they are stored in message queue;
|
|
* - denormalize the data from the message queue,
|
|
* - and get the data, as they will be transmitted to the GeneratorDriver
|
|
*
|
|
* @param array $options the options, as they are stored in the DocGeneratorTemplate (the admin form data)
|
|
* @param Person $entity The entity from which the data will be extracted
|
|
* @param array $data The data, from the public form
|
|
* @param array $expectedNormalized, how the normalized data are expected (allow to check that this data will be compliant with the storage in messenger queue)
|
|
* @param callable $assertionsOnData some test that will be executed on the normalized data
|
|
* @dataProvider provideNormalizedData
|
|
*/
|
|
public function testContextGenerationDataNormalizeDenormalizeGetData(
|
|
array $options,
|
|
Person $entity,
|
|
array $data,
|
|
array $expectedNormalized,
|
|
callable $assertionsOnData
|
|
): void {
|
|
// we boot kernel only for this test
|
|
self::bootKernel();
|
|
|
|
// we create a PersonContext with the minimal dependency injection needed (relying on
|
|
// prophecy for other dependencies)
|
|
$context = $this->buildPersonContext(
|
|
null,
|
|
self::$container->get(BaseContextData::class),
|
|
self::$container->get(CenterResolverManagerInterface::class),
|
|
self::$container->get(DocumentCategoryRepository::class),
|
|
self::$container->get(EntityManagerInterface::class),
|
|
self::$container->get(NormalizerInterface::class),
|
|
(new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => false]]])),
|
|
null,
|
|
self::$container->get(Security::class),
|
|
null,
|
|
null,
|
|
null,
|
|
self::$container->get(ThirdPartyRepository::class)
|
|
);
|
|
$template = new DocGeneratorTemplate();
|
|
$template->setName(["fr" => "test"])->setContext(AccompanyingPeriodContext::class)
|
|
->setDescription("description")->setActive(true)
|
|
->setOptions($options);
|
|
|
|
$normalized = $context->contextGenerationDataNormalize($template, $entity, $data);
|
|
|
|
self::assertEquals($expectedNormalized, $normalized);
|
|
|
|
$denormalized = $context->contextGenerationDataDenormalize($template, $entity, $normalized);
|
|
|
|
$data = $context->getData($template, $entity, $denormalized);
|
|
|
|
call_user_func($assertionsOnData, $data);
|
|
}
|
|
|
|
public function provideNormalizedData(): iterable
|
|
{
|
|
self::bootKernel();
|
|
$em = self::$container->get(EntityManagerInterface::class);
|
|
|
|
$thirdParty = $em->createQuery("SELECT t FROM " . ThirdParty::class . " t")
|
|
->setMaxResults(1)
|
|
->getSingleResult();
|
|
|
|
if (null === $thirdParty) {
|
|
throw new \RuntimeException("No thirdparty in database");
|
|
}
|
|
|
|
$person = $em->createQuery("SELECT p FROM " . Person::class . " p")
|
|
->setMaxResults(1)
|
|
->getSingleResult();
|
|
|
|
if (null === $person) {
|
|
throw new \RuntimeException("No confirmed period in database");
|
|
}
|
|
|
|
$category = self::$container->get(DocumentCategoryRepository::class)
|
|
->findAll()[0];
|
|
|
|
if (null === $category) {
|
|
throw new \RuntimeException("no document category in database");
|
|
}
|
|
|
|
yield [
|
|
[
|
|
'thirdParty' => true,
|
|
'thirdPartyLabel' => '3party',
|
|
'category' => $category,
|
|
],
|
|
$person,
|
|
[
|
|
'title' => 'test',
|
|
'thirdParty' => $thirdParty,
|
|
],
|
|
[
|
|
'thirdParty' => $thirdParty->getId(),
|
|
'title' => 'test',
|
|
'scope_id' => null,
|
|
],
|
|
function ($data) use ($person, $thirdParty) {
|
|
self::assertArrayHasKey('person', $data);
|
|
self::assertEquals($person->getId(), $data['person']['id']);
|
|
|
|
self::assertArrayHasKey('thirdParty', $data);
|
|
self::assertEquals($thirdParty->getId(), $data['thirdParty']['id']);
|
|
}
|
|
];
|
|
|
|
yield [
|
|
[
|
|
'thirdParty' => false,
|
|
'thirdPartyLabel' => '3party',
|
|
'category' => $category,
|
|
],
|
|
$person,
|
|
[
|
|
'title' => 'test',
|
|
],
|
|
[
|
|
'title' => 'test',
|
|
'scope_id' => null,
|
|
'thirdParty' => null,
|
|
],
|
|
function ($data) use ($person, $thirdParty) {
|
|
self::assertArrayHasKey('person', $data);
|
|
self::assertEquals($person->getId(), $data['person']['id']);
|
|
}
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Test that the build person context works in the case when 'form_show_scope' is false.
|
|
*/
|
|
public function testScopeDoNotShowScopeInForms()
|
|
{
|
|
$person = new Person();
|
|
$docGen = (new DocGeneratorTemplate())
|
|
->setName(['fr' => 'template']);
|
|
|
|
$parameter = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => false]]]);
|
|
$em = $this->prophesize(EntityManagerInterface::class);
|
|
$em->persist(Argument::type(PersonDocument::class))
|
|
->should(static function ($calls, $object, $method) {
|
|
if (1 !== count($calls)) {
|
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
|
}
|
|
|
|
/** @var PersonDocument $personDocument */
|
|
$personDocument = $calls[0]->getArguments()[0];
|
|
|
|
if (null !== $personDocument->getScope()) {
|
|
throw new FailedPredictionException('the person document should not have any scope');
|
|
}
|
|
});
|
|
|
|
$personContext = $this->buildPersonContext(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
$em->reveal(),
|
|
null,
|
|
$parameter
|
|
);
|
|
|
|
$personContext->buildPublicForm($this->buildFormBuilder(false), $docGen, $person);
|
|
|
|
$personContext->storeGenerated(
|
|
$docGen,
|
|
new StoredObject(),
|
|
$person,
|
|
[]
|
|
);
|
|
}
|
|
|
|
public function testScopeScopeMustBeShownInFormsAndUserAccessMultipleScope()
|
|
{
|
|
$person = new Person();
|
|
$docGen = (new DocGeneratorTemplate())
|
|
->setName(['fr' => 'template']);
|
|
$scope = new Scope();
|
|
|
|
$em = $this->prophesize(EntityManagerInterface::class);
|
|
$em->persist(Argument::type(PersonDocument::class))
|
|
->should(static function ($calls, $object, $method) use ($scope) {
|
|
if (1 !== count($calls)) {
|
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
|
}
|
|
|
|
/** @var PersonDocument $personDocument */
|
|
$personDocument = $calls[0]->getArguments()[0];
|
|
|
|
if ($personDocument->getScope() !== $scope) {
|
|
throw new FailedPredictionException('the person document should show the exactly prepared scope');
|
|
}
|
|
});
|
|
|
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
|
$authorizationHelper->getReachableScopes(Argument::type(UserInterface::class), PersonDocumentVoter::CREATE, Argument::type('array'))
|
|
->willReturn([$scope, new Scope()]);
|
|
|
|
$personContext = $this->buildPersonContext(
|
|
$authorizationHelper->reveal(),
|
|
null,
|
|
null,
|
|
null,
|
|
$em->reveal(),
|
|
);
|
|
|
|
$personContext->buildPublicForm($this->buildFormBuilder(true), $docGen, $person);
|
|
|
|
$personContext->storeGenerated(
|
|
$docGen,
|
|
new StoredObject(),
|
|
$person,
|
|
['scope' => $scope]
|
|
);
|
|
}
|
|
|
|
public function testScopeScopeMustBeShownInFormsAndUserAccessOneScope()
|
|
{
|
|
$person = new Person();
|
|
$docGen = (new DocGeneratorTemplate())
|
|
->setName(['fr' => 'template']);
|
|
$scope = new Scope();
|
|
|
|
$em = $this->prophesize(EntityManagerInterface::class);
|
|
$em->persist(Argument::type(PersonDocument::class))
|
|
->should(static function ($calls, $object, $method) use ($scope) {
|
|
if (1 !== count($calls)) {
|
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
|
}
|
|
|
|
/** @var PersonDocument $personDocument */
|
|
$personDocument = $calls[0]->getArguments()[0];
|
|
|
|
if ($personDocument->getScope() !== $scope) {
|
|
throw new FailedPredictionException('the person document should show the exactly prepared scope');
|
|
}
|
|
});
|
|
|
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
|
$authorizationHelper->getReachableScopes(Argument::type(UserInterface::class), PersonDocumentVoter::CREATE, Argument::type('array'))
|
|
->willReturn([$scope]);
|
|
|
|
$personContext = $this->buildPersonContext(
|
|
$authorizationHelper->reveal(),
|
|
null,
|
|
null,
|
|
null,
|
|
$em->reveal(),
|
|
);
|
|
|
|
$personContext->buildPublicForm($this->buildFormBuilder(true), $docGen, $person);
|
|
|
|
$personContext->storeGenerated(
|
|
$docGen,
|
|
new StoredObject(),
|
|
$person,
|
|
['scope' => $scope]
|
|
);
|
|
}
|
|
|
|
private function buildFormBuilder(bool $withScope): FormBuilderInterface
|
|
{
|
|
$builder = $this->prophesize(FormBuilderInterface::class);
|
|
|
|
$builder->add('title', TextType::class, Argument::type('array'))->shouldBeCalled();
|
|
|
|
if ($withScope) {
|
|
$builder->add('scope', ScopePickerType::class, Argument::type('array'))
|
|
->shouldBeCalled();
|
|
} else {
|
|
$builder->add('scope', ScopePickerType::class, Argument::type('array'))
|
|
->shouldNotBeCalled();
|
|
}
|
|
|
|
return $builder->reveal();
|
|
}
|
|
|
|
private function buildPersonContext(
|
|
?AuthorizationHelperInterface $authorizationHelper = null,
|
|
?BaseContextData $baseContextData = null,
|
|
?CenterResolverManagerInterface $centerResolverManager = null,
|
|
?DocumentCategoryRepository $documentCategoryRepository = null,
|
|
?EntityManagerInterface $em = null,
|
|
?NormalizerInterface $normalizer = null,
|
|
?ParameterBagInterface $parameterBag = null,
|
|
?ScopeRepositoryInterface $scopeRepository = null,
|
|
?Security $security = null,
|
|
?TranslatorInterface $translator = null,
|
|
?TranslatableStringHelperInterface $translatableStringHelper = null,
|
|
?ThirdPartyRender $thirdPartyRender = null,
|
|
?ThirdPartyRepository $thirdPartyRepository = null,
|
|
?ResidentialAddressRepository $residentialAddressRepository = null
|
|
): PersonContext {
|
|
if (null === $authorizationHelper) {
|
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class)->reveal();
|
|
}
|
|
|
|
if (null === $baseContextData) {
|
|
$baseContextData = $this->prophesize(BaseContextData::class)->reveal();
|
|
}
|
|
|
|
if (null === $centerResolverManager) {
|
|
$centerResolverManager = $this->prophesize(CenterResolverManagerInterface::class);
|
|
$centerResolverManager->resolveCenters(Argument::any(), Argument::any())
|
|
->willReturn([new Center()]);
|
|
$centerResolverManager = $centerResolverManager->reveal();
|
|
}
|
|
|
|
if (null === $documentCategoryRepository) {
|
|
$documentCategoryRepository = $this->prophesize(DocumentCategoryRepository::class);
|
|
$documentCategoryRepository->find(Argument::type('integer'))->willReturn(
|
|
new DocumentCategory(PersonDocument::class, 1)
|
|
);
|
|
$documentCategoryRepository = $documentCategoryRepository->reveal();
|
|
}
|
|
|
|
if (null === $em) {
|
|
$em = $this->prophesize(EntityManagerInterface::class)->reveal();
|
|
}
|
|
|
|
if (null === $normalizer) {
|
|
$normalizer = $this->prophesize(NormalizerInterface::class);
|
|
$normalizer->normalize(Argument::type(Person::class), 'docgen', Argument::any())
|
|
->willReturn(['type' => 'person']);
|
|
$normalizer = $normalizer->reveal();
|
|
}
|
|
|
|
if (null === $parameterBag) {
|
|
$parameterBag = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => true]]]);
|
|
}
|
|
|
|
if (null === $scopeRepository) {
|
|
$scopeRepository = $this->prophesize(ScopeRepositoryInterface::class);
|
|
$scopeRepository = $scopeRepository->reveal();
|
|
}
|
|
|
|
if (null === $security) {
|
|
$security = $this->prophesize(Security::class);
|
|
$security->getUser()->willReturn(new User());
|
|
$security = $security->reveal();
|
|
}
|
|
|
|
if (null === $translator) {
|
|
$translator = $this->prophesize(TranslatorInterface::class)->reveal();
|
|
}
|
|
|
|
if (null === $translatableStringHelper) {
|
|
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
|
// return only the 'fr' key
|
|
$translatableStringHelper->localize(Argument::type('array'))->will(static fn ($args) => $args[0]['fr']);
|
|
$translatableStringHelper = $translatableStringHelper->reveal();
|
|
}
|
|
|
|
if (null === $thirdPartyRender) {
|
|
$thirdPartyRender = $this->prophesize(ThirdPartyRender::class);
|
|
$thirdPartyRender = $thirdPartyRender->reveal();
|
|
}
|
|
|
|
if (null === $thirdPartyRepository) {
|
|
$thirdPartyRepository = $this->prophesize(ThirdPartyRepository::class);
|
|
$thirdPartyRepository = $thirdPartyRepository->reveal();
|
|
}
|
|
|
|
if (null === $residentialAddressRepository) {
|
|
$residentialAddressRepository = $this->prophesize(ResidentialAddressRepository::class);
|
|
$residentialAddressRepository->findCurrentResidentialAddressByPerson(Argument::type(Person::class), Argument::any())
|
|
->willReturn([
|
|
(new Person\ResidentialAddress())
|
|
->setAddress((new Address())
|
|
->setStreet('test street')
|
|
->setPostcode(new PostalCode()))
|
|
]);
|
|
$residentialAddressRepository = $residentialAddressRepository->reveal();
|
|
}
|
|
|
|
return new PersonContext(
|
|
$authorizationHelper,
|
|
$baseContextData,
|
|
$centerResolverManager,
|
|
$documentCategoryRepository,
|
|
$em,
|
|
$normalizer,
|
|
$parameterBag,
|
|
$scopeRepository,
|
|
$security,
|
|
$translator,
|
|
$translatableStringHelper,
|
|
$thirdPartyRender,
|
|
$thirdPartyRepository,
|
|
$residentialAddressRepository
|
|
);
|
|
}
|
|
}
|