diff --git a/phpstan-types.neon b/phpstan-types.neon index 9671c05a5..d43fd8944 100644 --- a/phpstan-types.neon +++ b/phpstan-types.neon @@ -460,8 +460,3 @@ parameters: count: 1 path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 1 - path: src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php - diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php index 08a0fec77..8e46feb7b 100644 --- a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php +++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php @@ -23,7 +23,7 @@ use function count; /** * Helps to find a summary of the budget: the sum of resources and charges. */ -class SummaryBudget +class SummaryBudget implements SummaryBudgetInterface { private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type'; @@ -52,26 +52,6 @@ class SummaryBudget $this->translatableStringHelper = $translatableStringHelper; } - public function getEmptyChargeArray(): array - { - $keys = $this->configRepository->getChargesKeys(); - $labels = $this->chargeLabels; - - return array_combine($keys, array_map(function ($i) use ($labels) { - return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; - }, $keys)); - } - - public function getEmptyResourceArray(): array - { - $keys = $this->configRepository->getResourcesKeys(); - $labels = $this->resourcesLabels; - - return array_combine($keys, array_map(function ($i) use ($labels) { - return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; - }, $keys)); - } - public function getSummaryForHousehold(?Household $household): array { if (null === $household) { @@ -101,8 +81,15 @@ class SummaryBudget ]; } - public function getSummaryForPerson(Person $person): array + public function getSummaryForPerson(?Person $person): array { + if (null === $person) { + return [ + 'resources' => $this->getEmptyResourceArray(), + 'charges' => $this->getEmptyChargeArray(), + ]; + } + $rsm = $this->buildRsm(); $resources = $this->em->createNativeQuery(self::QUERY_RESOURCE_BY_PERSON, $rsm) @@ -128,6 +115,26 @@ class SummaryBudget return $rsm; } + private function getEmptyChargeArray(): array + { + $keys = $this->configRepository->getChargesKeys(); + $labels = $this->chargeLabels; + + return array_combine($keys, array_map(function ($i) use ($labels) { + return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; + }, $keys)); + } + + private function getEmptyResourceArray(): array + { + $keys = $this->configRepository->getResourcesKeys(); + $labels = $this->resourcesLabels; + + return array_combine($keys, array_map(function ($i) use ($labels) { + return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])]; + }, $keys)); + } + private function rowToArray(array $rows, string $kind): array { switch ($kind) { diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php new file mode 100644 index 000000000..528c4626e --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php @@ -0,0 +1,25 @@ +entityPut('_entity', $request, $id, $_format); case Request::METHOD_POST: - return $this->entityPostAction('_entity', $request, $id, $_format); + return $this->entityPostAction('_entity', $request, $id); case Request::METHOD_DELETE: return $this->entityDelete('_entity', $request, $id, $_format); diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 59570f956..7bde8a524 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -276,25 +276,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI /** * The person's first name. * - * @var string - * * @ORM\Column(type="string", length=255) * @Assert\NotBlank(message="The firstname cannot be empty") * @Assert\Length( * max=255, * ) */ - private $firstName; + private string $firstName = ''; /** * fullname canonical. Read-only field, which is calculated by * the database. * - * @var string - * * @ORM\Column(type="text", nullable=true) */ - private $fullnameCanonical; + private string $fullnameCanonical = ''; /** * The person's gender. @@ -345,15 +341,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI /** * The person's last name. * - * @var string - * * @ORM\Column(type="string", length=255) * @Assert\NotBlank(message="The lastname cannot be empty") * @Assert\Length( * max=255, * ) */ - private $lastName; + private string $lastName = ''; /** * The marital status of the person. @@ -1583,9 +1577,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } - public function setFirstName(string $firstName): self + public function setFirstName(?string $firstName): self { - $this->firstName = $firstName; + $this->firstName = (string) $firstName; return $this; } @@ -1611,9 +1605,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this; } - public function setLastName(string $lastName): self + public function setLastName(?string $lastName): self { - $this->lastName = $lastName; + $this->lastName = (string) $lastName; return $this; } diff --git a/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php b/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php index aeab09fea..31af0a649 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php @@ -29,8 +29,12 @@ use Symfony\Contracts\Translation\TranslatorInterface; final class PersonResourceType extends AbstractType { + private PersonRenderInterface $personRender; + private ResourceKindRender $resourceKindRender; + private ThirdPartyRender $thirdPartyRender; + private TranslatorInterface $translator; public function __construct(ResourceKindRender $resourceKindRender, PersonRenderInterface $personRender, ThirdPartyRender $thirdPartyRender, TranslatorInterface $translator) diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php index 28216f368..490a7e2af 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonDocGenNormalizer.php @@ -11,7 +11,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Serializer\Normalizer; -use Chill\BudgetBundle\Service\Summary\SummaryBudget; +use Chill\BudgetBundle\Service\Summary\SummaryBudgetInterface; use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper; use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Civility; @@ -45,7 +45,7 @@ class PersonDocGenNormalizer implements private RelationshipRepository $relationshipRepository; - private SummaryBudget $summaryBudget; + private SummaryBudgetInterface $summaryBudget; private TranslatableStringHelper $translatableStringHelper; @@ -56,7 +56,7 @@ class PersonDocGenNormalizer implements RelationshipRepository $relationshipRepository, TranslatorInterface $translator, TranslatableStringHelper $translatableStringHelper, - SummaryBudget $summaryBudget + SummaryBudgetInterface $summaryBudget ) { $this->personRender = $personRender; $this->relationshipRepository = $relationshipRepository; @@ -214,6 +214,14 @@ class PersonDocGenNormalizer implements $data['relations'] = []; } + if ($context['docgen:person:with-budget'] ?? false) { + $data['budget']['person'] = $this->summaryBudget->getSummaryForPerson(null); + + if ($context['docgen:person:with-household'] ?? false) { + $data['budget']['household'] = $this->summaryBudget->getSummaryForHousehold(null); + } + } + return $data; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php index 08034978e..94a0ac243 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php @@ -65,7 +65,7 @@ final class HouseholdApiControllerTest extends WebTestCase } $reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar') - ->setFirstResult(random_int(0, $nbReference)) + ->setFirstResult(random_int(0, $nbReference - 1)) ->setMaxResults(1) ->getQuery()->getSingleResult(); diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php index c19533e08..deef94525 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php @@ -11,6 +11,7 @@ declare(strict_types=1); namespace Serializer\Normalizer; +use Chill\BudgetBundle\Service\Summary\SummaryBudgetInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Entity\Household\Household; @@ -72,6 +73,17 @@ final class PersonDocGenNormalizerTest extends KernelTestCase $this->normalizer = self::$container->get(NormalizerInterface::class); } + public function dataGeneratorNormalizationNullOrNotNullHaveSameKeys(): iterable + { + yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read']]]; + + yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-household' => true]]; + + yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-relations' => true]]; + + yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-budget' => true]]; + } + public function generateData() { $person = new Person(); @@ -90,12 +102,16 @@ final class PersonDocGenNormalizerTest extends KernelTestCase yield [null, self::BLANK, 'normalization for a null person']; } - public function testNormalizationNullOrNotNullHaveSameKeys() + /** + * @dataProvider dataGeneratorNormalizationNullOrNotNullHaveSameKeys + * + * @param mixed $context + */ + public function testNormalizationNullOrNotNullHaveSameKeys($context) { - $this->markTestSkipped(); $period = new Person(); - $notNullData = $this->buildPersonNormalizer()->normalize($period, 'docgen', ['docgen:expects' => Person::class]); - $nullData = $this->buildPersonNormalizer()->normalize(null, 'docgen', ['docgen:expects' => Person::class]); + $notNullData = $this->buildPersonNormalizer()->normalize($period, 'docgen', $context); + $nullData = $this->buildPersonNormalizer()->normalize(null, 'docgen', $context); $this->assertEqualsCanonicalizing( array_keys($notNullData), @@ -131,7 +147,6 @@ final class PersonDocGenNormalizerTest extends KernelTestCase public function testNormalizePersonWithHousehold() { - $this->markTestSkipped(); $household = new Household(); $person = new Person(); $person @@ -172,7 +187,6 @@ final class PersonDocGenNormalizerTest extends KernelTestCase public function testNormalizePersonWithRelationships() { - $this->markTestSkipped(); $person = (new Person())->setFirstName('Renaud')->setLastName('megane'); $father = (new Person())->setFirstName('Clément')->setLastName('megane'); $mother = (new Person())->setFirstName('Mireille')->setLastName('Mathieu'); @@ -235,13 +249,25 @@ final class PersonDocGenNormalizerTest extends KernelTestCase ?RelationshipRepository $relationshipRepository = null, ?TranslatorInterface $translator = null, ?TranslatableStringHelper $translatableStringHelper = null, - ?NormalizerInterface $normalizer = null + ?NormalizerInterface $normalizer = null, + ?SummaryBudgetInterface $summaryBudget = null ): PersonDocGenNormalizer { + if (null === $summaryBudget) { + $summaryBudget = $this->prophesize(SummaryBudgetInterface::class); + $summaryBudget->getSummaryForHousehold(Argument::any())->willReturn( + ['resources' => [], 'charges' => []] + ); + $summaryBudget->getSummaryForPerson(Argument::any())->willReturn( + ['resources' => [], 'charges' => []] + ); + } + $personDocGenNormalizer = new PersonDocGenNormalizer( $personRender ?? self::$container->get(PersonRender::class), $relationshipRepository ?? self::$container->get(RelationshipRepository::class), $translator ?? self::$container->get(TranslatorInterface::class), - $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class) + $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class), + $summaryBudget->reveal(), ); if (null === $normalizer) { @@ -259,13 +285,31 @@ final class PersonDocGenNormalizerTest extends KernelTestCase ?PersonRender $personRender = null, ?RelationshipRepository $relationshipRepository = null, ?TranslatorInterface $translator = null, - ?TranslatableStringHelper $translatableStringHelper = null + ?TranslatableStringHelper $translatableStringHelper = null, + ?SummaryBudgetInterface $summaryBudget = null ): PersonDocGenNormalizer { + if (null === $relationshipRepository) { + $relationshipRepository = $this->prophesize(RelationshipRepository::class); + $relationshipRepository->findByPerson(Argument::type(Person::class))->willReturn([]); + $relationshipRepository = $relationshipRepository->reveal(); + } + + if (null === $summaryBudget) { + $summaryBudget = $this->prophesize(SummaryBudgetInterface::class); + $summaryBudget->getSummaryForHousehold(Argument::any())->willReturn( + ['resources' => [], 'charges' => []] + ); + $summaryBudget->getSummaryForPerson(Argument::any())->willReturn( + ['resources' => [], 'charges' => []] + ); + } + $normalizer = new PersonDocGenNormalizer( $personRender ?? self::$container->get(PersonRender::class), - $relationshipRepository ?? self::$container->get(RelationshipRepository::class), + $relationshipRepository, $translator ?? self::$container->get(TranslatorInterface::class), - $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class) + $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class), + $summaryBudget->reveal() ); $normalizerManager = $this->prophesize(NormalizerInterface::class); $normalizerManager->supportsNormalization(Argument::any(), 'docgen', Argument::any())->willReturn(true); diff --git a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php index cec9dee7d..4fe3da927 100644 --- a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php +++ b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php @@ -71,13 +71,13 @@ class ThirdPartyRender extends AbstractChillEntityRender $civility = ''; } - if (!empty($entity->getAcronym())) { + if ('' !== (string) $entity->getAcronym()) { $acronym = ' (' . $entity->getAcronym() . ')'; } else { $acronym = ''; } - $firstname = empty($entity->getFirstname()) ? '' : $entity->getFirstname(); + $firstname = ('' === $entity->getFirstname()) ? '' : $entity->getFirstname(); return $civility . $firstname . ' ' . $entity->getName() . $acronym; }