From c1b9069138a53a7cb0949cb6c00b0178bb7b85ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Apr 2016 23:59:14 +0200 Subject: [PATCH] fix the possibility to add multiple participation ref #6 --- Controller/ParticipationController.php | 99 ++++++++++++-- Resources/translations/messages.fr.yml | 2 + .../_ignored_participations.html.twig | 10 ++ .../Participation/new-multiple.html.twig | 5 +- Resources/views/Participation/new.html.twig | 5 + .../ParticipationControllerTest.php | 122 +++++++++++++++++- 6 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 Resources/views/Participation/_ignored_participations.html.twig diff --git a/Controller/ParticipationController.php b/Controller/ParticipationController.php index 007a7825d..e2eaa3fa2 100644 --- a/Controller/ParticipationController.php +++ b/Controller/ParticipationController.php @@ -39,7 +39,8 @@ class ParticipationController extends Controller * Show a form to add a participation * * This function parse the person_id / persons_ids query argument - * and decide if it should process a single or multiple participation + * and decide if it should process a single or multiple participation. Depending + * on this, the appropriate layout and form. * * @param Request $request */ @@ -76,7 +77,18 @@ class ParticipationController extends Controller . "'persons_ids' argument in query"); } - protected function testRequest($request) + /** + * + * Test that the query parameters are valid : + * + * - an `event_id` is existing ; + * - `person_id` and `persons_ids` are **not** both present ; + * - `persons_id` is correct (contains only numbers and a ','. + * + * @param Request $request + * @throws \RuntimeException if an error is detected + */ + protected function testRequest(Request $request) { $single = $request->query->has('person_id'); $multiple = $request->query->has('persons_ids'); @@ -103,6 +115,12 @@ class ParticipationController extends Controller } + /** + * Show a form with single participation. + * + * @param Request $request + * @return Response + */ protected function newSingle(Request $request) { $participation = $this->handleRequest($request, new Participation()); @@ -114,25 +132,84 @@ class ParticipationController extends Controller return $this->render('ChillEventBundle:Participation:new.html.twig', array( 'form' => $form->createView(), - 'participation' => $participation + 'participation' => $participation, + 'ignored_participations' => array() // this is required, see self::newMultiple )); } + /** + * Show a form with multiple participation. + * + * If a person is already participating on the event (if a participation with + * the same person is associated with the event), the participation is ignored. + * + * If all but one participation is ignored, the page show the same response + * than the newSingle function. + * + * If all participations must be ignored, an error is shown and the method redirects + * to the event 'show' view with an appropriate flash message. + * + * @param Request $request + * @return Response + */ protected function newMultiple(Request $request) { $participations = $this->handleRequest($request, new Participation()); - foreach ($participations as $participation) { + foreach ($participations as $i => $participation) { + // check for authorization $this->denyAccessUnlessGranted(ParticipationVoter::CREATE, $participation, 'The user is not allowed to create this participation'); + + // check that the user is not already in the event (computing only once) + /* @var $peopleParticipating \Doctrine\Common\Collections\ArrayCollection */ + $peopleParticipating = isset($peopleParticipating) ? $peopleParticipating : + $participation->getEvent()->getParticipations()->map( + function(Participation $p) { return $p->getPerson()->getId(); } + ); + + if ($peopleParticipating->contains($participation->getPerson()->getId())) { + $ignoredParticipations[] = $participation + ->getEvent()->getParticipations()->filter( + function (Participation $p) use ($participation) { + return $p->getPerson()->getId() === $participation->getPerson()->getId(); + } + )->first(); + } else { + $newParticipations[] = $participation; + } } - $form = $this->createCreateFormMultiple($participations); + // this is where the function redirect depending on valid participation - return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', array( - 'form' => $form->createView(), - 'participations' => $participations - )); + if (!isset($newParticipations)) { + // if we do not have nay participants, redirect to event view + $this->addFlash('error', 'Any of the requested people may be added ' + . 'on the event: they are maybe already participating.'); + + return $this->redirectToRoute('chill_event_participation_new', array( + 'event_id' => $request->query->getInt('event_id', 0) + )); + } elseif (count($newParticipations) > 1) { + // if we have multiple participations, show a form with multiple participations + $form = $this->createCreateFormMultiple($newParticipations); + + return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', array( + 'form' => $form->createView(), + 'participations' => $newParticipations, + 'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() + )); + } else { + // if we have only one participation, show the same form than for single participation + $form = $this->createCreateForm($participation); + + return $this->render('ChillEventBundle:Participation:new.html.twig', array( + 'form' => $form->createView(), + 'participation' => $participation, + 'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() + )); + + } } public function createAction(Request $request) @@ -338,7 +415,7 @@ class ParticipationController extends Controller $form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class, array('participations' => $participations), array( 'action' => $this->generateUrl('chill_event_participation_create', array( - 'event_id' => $participations[0]->getEvent()->getId(), + 'event_id' => current($participations)->getEvent()->getId(), 'persons_ids' => implode(',', array_map( function(Participation $p) { return $p->getPerson()->getId(); }, $participations)) @@ -347,7 +424,7 @@ class ParticipationController extends Controller $form->add('participations', CollectionType::class, array( 'entry_type' => ParticipationType::class, 'entry_options' => array( - 'event_type' => $participations[0]->getEvent()->getType() + 'event_type' => current($participations)->getEvent()->getType() ), ) ); diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 67e992d7e..3d1d9c4ca 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -32,6 +32,8 @@ Back to the event: Retour à l'événement The participation was created: La participation a été créée The participation was updated: La participation a été mise à jour Participation Edit: Modifier une participation +'Any of the requested people may be added on the event: they are maybe already participating.': 'Aucune des personnes suggérées ne peut être ajoutée à l''événement: elles sont peut-être déjà inscrites comme participantes.' +'The following people have been ignored because they are already participating on the event': '{1} La personne suivante a été ignorée parce qu''elle participe déjà à l''événement | ]1,Inf] Les personnes suivantes ont été ignorées parce qu''elles participent déjà à l''événement' #search Event search: Recherche d'événements diff --git a/Resources/views/Participation/_ignored_participations.html.twig b/Resources/views/Participation/_ignored_participations.html.twig new file mode 100644 index 000000000..0d54dd624 --- /dev/null +++ b/Resources/views/Participation/_ignored_participations.html.twig @@ -0,0 +1,10 @@ +{% import 'ChillPersonBundle:Person:macro.html.twig' as person_macro %} + +{% if ignored_participations|length > 0 %} +

{% transchoice ignored_participations|length %}The following people have been ignored because they are already participating on the event{% endtranschoice %} :

+ +{% endif %} \ No newline at end of file diff --git a/Resources/views/Participation/new-multiple.html.twig b/Resources/views/Participation/new-multiple.html.twig index 634ffa78f..8cdfed800 100644 --- a/Resources/views/Participation/new-multiple.html.twig +++ b/Resources/views/Participation/new-multiple.html.twig @@ -28,8 +28,8 @@ - - + + {% include 'ChillEventBundle:Participation:_ignored_participations.html.twig' with ignored_participations %} {{ form_start(form) }} @@ -64,4 +64,5 @@ {{ form_end(form) }} + {% endblock %} diff --git a/Resources/views/Participation/new.html.twig b/Resources/views/Participation/new.html.twig index f74aef392..7ec10fa5f 100644 --- a/Resources/views/Participation/new.html.twig +++ b/Resources/views/Participation/new.html.twig @@ -19,6 +19,8 @@
+ + {% include 'ChillEventBundle:Participation:_ignored_participations.html.twig' with ignored_participations %} {{ form_start(form) }} @@ -26,6 +28,8 @@ {{ form_row(form.role) }} {{ form_row(form.status) }} + + {{ form_end(form) }} + {% endblock %} diff --git a/Tests/Controller/ParticipationControllerTest.php b/Tests/Controller/ParticipationControllerTest.php index b9a6d8dde..d912b206f 100644 --- a/Tests/Controller/ParticipationControllerTest.php +++ b/Tests/Controller/ParticipationControllerTest.php @@ -44,7 +44,9 @@ class ParticipationControllerTest extends WebTestCase /** * Keep a cache for each person id given by the function getRandomPerson. * - * This is reset by setUp() + * You may ask to ignore some people by adding their id to the array. + * + * This is reset by setUp(). * * @var int[] */ @@ -92,8 +94,31 @@ class ParticipationControllerTest extends WebTestCase } /** + * Return a random event only if he has more than one participation. + * + * @param string $centerName + * @param type $circleName + * @return \Chill\EventBundle\Entity\Event + */ + protected function getRandomEventWithMultipleParticipations( + $centerName = 'Center A', + $circleName = 'social') + { + $event = $this->getRandomEvent($centerName, $circleName); + + return $event->getParticipations()->count() > 1 ? + $event : + $this->getRandomEventWithMultipleParticipations($centerName, $circleName); + } + + /** + * Returns a person randomly. + * * This function does not give the same person twice - * for each test + * for each test. + * + * You may ask to ignore some people by adding their id to the property + * `$this->personsIdsCache` * * @param string $centerName * @return \Chill\PersonBundle\Entity\Person @@ -226,7 +251,7 @@ class ParticipationControllerTest extends WebTestCase 'person_id' => $person->getId(), 'event_id' => $event->getId() )); - + $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "test that /fr/event/participation/new is successful"); @@ -257,8 +282,17 @@ class ParticipationControllerTest extends WebTestCase public function testNewMultipleAction() { $event = $this->getRandomEvent(); - // record the number of participation for the event + // record the number of participation for the event (used later in this test) $nbParticipations = $event->getParticipations()->count(); + // make ignore the people already in the event from the function getRandomPerson + $this->personsIdsCache = array_merge( + $this->personsIdsCache, + $event->getParticipations()->map( + function($p) { return $p->getPerson()->getId(); } + ) + ->toArray() + ); + // get some random people $person1 = $this->getRandomPerson(); $person2 = $this->getRandomPerson(); @@ -267,7 +301,7 @@ class ParticipationControllerTest extends WebTestCase 'persons_ids' => implode(',', array($person1->getId(), $person2->getId())), 'event_id' => $event->getId() )); - + $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), "test that /fr/event/participation/new is successful"); @@ -307,5 +341,83 @@ class ParticipationControllerTest extends WebTestCase $this->assertEquals($nbParticipations + 2, $event->getParticipations()->count()); } + public function testMultipleWithAllPeopleParticipating() + { + $event = $this->getRandomEventWithMultipleParticipations(); + + $persons_id = implode(',', $event->getParticipations()->map( + function($p) { return $p->getPerson()->getId(); } + )->toArray()); + + $crawler = $this->client->request('GET', '/fr/event/participation/new', + array( + 'persons_ids' => $persons_id, + 'event_id' => $event->getId() + )); + + $this->assertEquals(302, $this->client->getResponse()->getStatusCode(), + "test that /fr/event/participation/new is redirecting"); + } + + public function testMultipleWithSomePeopleParticipating() + { + $event = $this->getRandomEventWithMultipleParticipations(); + // record the number of participation for the event (used later in this test) + $nbParticipations = $event->getParticipations()->count(); + // get the persons_id participating on this event + $persons_id = $event->getParticipations()->map( + function($p) { return $p->getPerson()->getId(); } + )->toArray(); + // exclude the existing persons_ids from the new person + $this->personsIdsCache = array_merge($this->personsIdsCache, $persons_id); + + // get a random person + $newPerson = $this->getRandomPerson(); + + // build the `persons_ids` parameter + $persons_ids_string = implode(',', array_merge($persons_id, + array($newPerson->getId()))); + + $crawler = $this->client->request('GET', '/fr/event/participation/new', + array( + 'persons_ids' => $persons_ids_string, + 'event_id' => $event->getId() + )); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), + "test that /fr/event/participation/new is successful"); + + // count that the one UL contains the new person string + $firstPerson = $event->getParticipations()->first()->getPerson(); + $ul = $crawler->filter('ul:contains("'.$firstPerson->getLastName().'")' + . ':contains("'.$firstPerson->getFirstName().'")'); + + $this->assertEquals(1, $ul->count(), + "assert an ul containing the name of ignored people is present"); + $this->assertEquals($event->getParticipations()->count(), $ul->children()->count(), + "assert the li listing ignored people has the correct number"); + + // test a form is present on the page + $button = $crawler->selectButton('Créer'); + + $this->assertNotNull($button, "test the form with button 'Créer' exists"); + + // submit the form + $this->client->submit($button->form(), array( + 'participation[role]' => $event->getType()->getRoles()->first()->getId(), + 'participation[status]' => $event->getType()->getStatuses()->first()->getId() + )); + + $this->assertTrue($this->client->getResponse()->isRedirect()); + + // reload the event and test there is a new participation + $event = $this->em->getRepository('ChillEventBundle:Event') + ->find($event->getId()); + $this->em->refresh($event); + + $this->assertEquals($nbParticipations + 1, $event->getParticipations()->count(), + "Test we have persisted a new participation associated to the test"); + } + }