From a8bf478ee8db0b519363f3db5c4e68b598abc430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 27 Jun 2021 11:10:17 +0200 Subject: [PATCH 1/6] add endpoint for getting suggestion on household by accompanying period --- .../Controller/HouseholdApiController.php | 35 ++++++++ .../ChillPersonExtension.php | 7 ++ .../Household/HouseholdRepository.php | 89 ++++++++++++++++++- .../ChillPersonBundle/chill.api.specs.yaml | 30 +++++++ 4 files changed, 160 insertions(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php index 67f70db40..1e15490dc 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php @@ -4,15 +4,50 @@ namespace Chill\PersonBundle\Controller; use Chill\MainBundle\CRUD\Controller\ApiController; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Serializer\Model\Collection; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Repository\Household\HouseholdRepository; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; class HouseholdApiController extends ApiController { + private HouseholdRepository $householdRepository; + + public function __construct(HouseholdRepository $householdRepository) + { + $this->householdRepository = $householdRepository; + } + public function householdAddressApi($id, Request $request, string $_format): Response { return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]); } + /** + * Find Household of people participating to the same AccompanyingPeriod + * + * @ParamConverter("person", options={"id" = "person_id"}) + */ + public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format) + { + // TODO add acl + + $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person); + $paginator = $this->getPaginatorFactory()->create($count); + + if ($count === 0) { + $households = []; + } else { + $households = $this->householdRepository->findByAccompanyingPeriodParticipation($person, + $paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber()); + } + + $collection = new Collection($households, $paginator); + + return $this->json($collection, Response::HTTP_OK, [], + [ "groups" => ["read"]]); + } } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 733579acb..03b05bbc8 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -565,6 +565,13 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ], 'controller_action' => 'householdAddressApi' ], + 'suggestHouseholdByAccompanyingPeriodParticipation' => [ + 'path' => '/suggest/by-person/{person_id}/through-accompanying-period-participation.{_format}', + 'methods' => [ + Request::METHOD_GET => true, + Request::METHOD_HEAD => true, + ] + ] ] ], [ diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php index b7a8816b3..d9ec6c35e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php @@ -3,15 +3,102 @@ namespace Chill\PersonBundle\Repository\Household; use Chill\PersonBundle\Entity\Household\Household; +use Chill\PersonBundle\Entity\Person; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\ResultSetMappingBuilder; +use Doctrine\Persistence\ObjectRepository; -final class HouseholdRepository +final class HouseholdRepository implements ObjectRepository { private EntityRepository $repository; + private EntityManagerInterface $em; public function __construct(EntityManagerInterface $entityManager) { $this->repository = $entityManager->getRepository(Household::class); + $this->em = $entityManager; } + + public function find($id) + { + return $this->repository->find($id); + } + + public function findAll() + { + return $this->repository->findAll(); + } + + public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null) + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria) + { + return $this->findOneBy($criteria); + } + + public function getClassName() + { + return Household::class; + } + + public function countByAccompanyingPeriodParticipation(Person $person) + { + return $this->buildQueryByAccompanyingPeriodParticipation($person, true); + } + + public function findByAccompanyingPeriodParticipation(Person $person, int $limit, int $offset) + { + return $this->buildQueryByAccompanyingPeriodParticipation($person, false, $limit, $offset); + } + + private function buildQueryByAccompanyingPeriodParticipation(Person $person, bool $isCount = false, int $limit = 50, int $offset = 0) + { + $rsm = new ResultSetMappingBuilder($this->em); + $rsm->addRootEntityFromClassMetadata(Household::class, 'h'); + + if ($isCount) { + $rsm->addScalarResult('count', 'count'); + $sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ + '{select}' => 'COUNT(households.*) AS count', + '{limits}' => '' + ]); + } else { + $sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [ + '{select}' => $rsm->generateSelectClause(['h' => 'households']), + '{limits}' => "OFFSET {$offset} LIMIT {$limit}" + ]); + } + $native = $this->em->createNativeQuery($sql, $rsm); + $native->setParameters([0 => $person->getId(), 1 => $person->getId()]); + + if ($isCount) { + return $native->getSingleScalarResult(); + } else { + return $native->getResult(); + } + } + + private CONST SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION = << Date: Mon, 28 Jun 2021 00:35:40 +0200 Subject: [PATCH 2/6] show household suggestion in household members editor --- .../vuejs/HouseholdMembersEditor/api.js | 15 ++++ .../components/Household.vue | 75 ++++++++++++++++++- .../vuejs/HouseholdMembersEditor/js/i18n.js | 4 + .../HouseholdMembersEditor/store/index.js | 54 ++++++++++++- 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/api.js index 27318ba0a..e54bd9b15 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/api.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/api.js @@ -23,6 +23,21 @@ const householdMove = (payload) => { }); }; +const fetchHouseholdSuggestionByAccompanyingPeriod = (personId) => { + const url = `/api/1.0/person/household/suggest/by-person/${personId}/through-accompanying-period-participation.json`; + return window.fetch(url) + .then(response => { + if (response.ok) { + return response.json(); + } + + throw Error ({m: 'Error while fetching household suggestion', status: response.status}); + }).then(data => Promise.resolve(data.results)) + .catch(e => console.err(e)); + ; +}; + export { householdMove, + fetchHouseholdSuggestionByAccompanyingPeriod, }; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue index d9312cf00..6901b3992 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Household.vue @@ -14,6 +14,23 @@ + +
+
+

{{ $t('household_members_editor.household_for_participants_accompanying_period') }}:

+
+
+ + +
    +
  • + +
  • +
+
+
+
+
+ + {{ encore_entry_script_tags('household_members_editor') }} {% endblock %} From e8566fd0064ef747a0af8471dbfba23f288a81e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 28 Jun 2021 12:36:19 +0200 Subject: [PATCH 4/6] change label --- .../Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js index c09f6a365..fa0121157 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/js/i18n.js @@ -13,7 +13,7 @@ const appMessages = { leave_without_household: "Sans nouveau ménage" }, concerned: { - title: "Usagers concernés", + title: "Nouveaux membres du ménage", add_persons: "Ajouter d'autres usagers", search: "Rechercher des usagers", move_to: "Déplacer vers", From 2a1f5cbad10858da02f0b89edd6face9d8976930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 28 Jun 2021 13:18:00 +0200 Subject: [PATCH 5/6] add test for suggestion household by accompanying period --- .../Controller/HouseholdApiControllerTest.php | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php new file mode 100644 index 000000000..f6adc5d01 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php @@ -0,0 +1,55 @@ +getClientAuthenticated(); + + $client->request( + Request::METHOD_GET, + "/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json" + ); + + $this->assertResponseIsSuccessful(); + } + + public function generatePersonId() + { + self::bootKernel(); + + $qb = self::$container->get(EntityManagerInterface::class) + ->createQueryBuilder(); + + $period = $qb + ->select('ap') + ->from(AccompanyingPeriod::class, 'ap') + ->where( + $qb->expr()->gte('SIZE(ap.participations)', 2) + ) + ->getQuery() + ->setMaxResults(1) + ->getSingleResult() + ; + + $person = $period->getParticipations() + ->first()->getPerson(); + + yield [ $person->getId() ]; + } +} From 6eaffcae4986620f7ba2a81a3a4c5b74d98b786e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 28 Jun 2021 16:22:17 +0200 Subject: [PATCH 6/6] fix redirection after changing household member --- .../public/vuejs/HouseholdMembersEditor/store/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js index b44278614..a670685c0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/store/index.js @@ -303,7 +303,7 @@ const store = createStore({ if (household.type === 'household') { household_id = household.id; // nothing to do anymore here, bye-bye ! - window.location.replace(`/fr/person/household/${household_id}/members`); + window.location.replace(`/fr/person/household/${household_id}/summary`); } else { // we assume the answer was 422... error = household;