From ff5bda12b66df0accfb6167f7eacdc5fc0414cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sun, 13 Mar 2016 22:14:40 +0100 Subject: [PATCH] add new / create address + tests --- Controller/PersonAddressController.php | 110 +++++++++- Entity/Person.php | 21 +- Resources/config/doctrine/Person.orm.yml | 1 + Resources/config/routing.yml | 13 ++ Resources/translations/messages.fr.yml | 6 + Resources/views/Address/edit.html.twig | 15 +- Resources/views/Address/list.html.twig | 84 ++++++++ Resources/views/Address/new.html.twig | 47 +++++ Resources/views/Person/view.html.twig | 8 +- .../PersonAddressControllerTest.php | 189 ++++++++++++++++++ 10 files changed, 477 insertions(+), 17 deletions(-) create mode 100644 Resources/views/Address/list.html.twig create mode 100644 Resources/views/Address/new.html.twig create mode 100644 Tests/Controller/PersonAddressControllerTest.php diff --git a/Controller/PersonAddressController.php b/Controller/PersonAddressController.php index 6dcea9de1..f76719344 100644 --- a/Controller/PersonAddressController.php +++ b/Controller/PersonAddressController.php @@ -37,6 +37,92 @@ use Symfony\Component\HttpFoundation\Request; */ class PersonAddressController extends Controller { + + public function listAction($person_id) + { + $person = $this->getDoctrine()->getManager() + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if ($person === NULL) { + throw $this->createNotFoundException("Person with id $person_id not" + . " found "); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, + "You are not allowed to edit this person."); + + return $this->render('ChillPersonBundle:Address:list.html.twig', array( + 'person' => $person + )); + } + + public function newAction($person_id) + { + $person = $this->getDoctrine()->getManager() + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if ($person === NULL) { + throw $this->createNotFoundException("Person with id $person_id not" + . " found "); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person, + "You are not allowed to edit this person."); + + $address = new Address(); + + $form = $this->createCreateForm($person, $address); + + return $this->render('ChillPersonBundle:Address:new.html.twig', array( + 'person' => $person, + 'form' => $form->createView() + )); + } + + public function createAction($person_id, Request $request) + { + $person = $this->getDoctrine()->getManager() + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if ($person === NULL) { + throw $this->createNotFoundException("Person with id $person_id not" + . " found "); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person, + "You are not allowed to edit this person."); + + $address = new Address(); + + $form = $this->createCreateForm($person, $address); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $address = $form->getData(); + $person->addAddress($address); + + $em = $this->getDoctrine()->getManager(); + $em->flush(); + + $this->addFlash('success', + $this->get('translator')->trans('The new address was created successfully') + ); + + return $this->redirectToRoute('chill_person_address_list', array( + 'person_id' => $person->getId() + )); + } + + return $this->render('ChillPersonBundle:Address:new.html.twig', array( + 'person' => $person, + 'form' => $form->createView() + )); + } + public function editAction($person_id, $address_id) { $person = $this->getDoctrine()->getManager() @@ -91,7 +177,7 @@ class PersonAddressController extends Controller $this->addFlash('success', $this->get('translator')->trans( "The address has been successfully updated")); - return $this->redirectToRoute('chill_person_view', array( + return $this->redirectToRoute('chill_person_address_list', array( 'person_id' => $person->getId() )); } @@ -126,6 +212,28 @@ class PersonAddressController extends Controller return $form; } + /** + * + * @param Person $person + * @param Address $address + * @return \Symfony\Component\Form\Form + */ + protected function createCreateForm(Person $person, Address $address) + { + $form = $this->createForm(AddressType::class, $address, array( + 'method' => 'POST', + 'action' => $this->generateUrl('chill_person_address_create', array( + 'person_id' => $person->getId() + )) + )); + + $form->add('submit', 'submit', array( + 'label' => 'Submit' + )); + + return $form; + } + /** * * @param Person $person diff --git a/Entity/Person.php b/Entity/Person.php index fda72bb54..b357fafb2 100644 --- a/Entity/Person.php +++ b/Entity/Person.php @@ -619,8 +619,10 @@ class Person implements HasCenterInterface { } /** + * By default, the addresses are ordered by date, descending (the most + * recent first) * - * @return \Chill\MainBundle\Entity\Address[]@return Address[] + * @return \Chill\MainBundle\Entity\Address[] */ public function getAddresses() { @@ -633,21 +635,14 @@ class Person implements HasCenterInterface { $date = new \DateTime('now'); } - $lastAddress = null; + $addresses = $this->getAddresses(); - foreach ($this->getAddresses() as $address) { - if ($address->getValidFrom() < $date) { - if ($lastAddress === NULL) { - $lastAddress = $address; - } else { - if ($lastAddress->getValidFrom() < $address->getValidFrom()) { - $lastAddress = $address; - } - } - } + if ($addresses == null) { + + return null; } - return $lastAddress; + return $addresses->first(); } /** diff --git a/Resources/config/doctrine/Person.orm.yml b/Resources/config/doctrine/Person.orm.yml index 60f128a11..e566ddc7e 100644 --- a/Resources/config/doctrine/Person.orm.yml +++ b/Resources/config/doctrine/Person.orm.yml @@ -74,6 +74,7 @@ Chill\PersonBundle\Entity\Person: referencedColumnName: id addresses: targetEntity: Chill\MainBundle\Entity\Address + orderBy: { 'validFrom': 'DESC' } joinTable: name: chill_person_persons_to_addresses cascade: [persist, remove, merge, detach] diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index d9983e849..927eb59e5 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -70,6 +70,19 @@ chill_person_accompanying_period_open: path: /{_locale}/person/{person_id}/accompanying-period/open defaults: { _controller: ChillPersonBundle:AccompanyingPeriod:open } +chill_person_address_list: + path: /{_locale}/person/{person_id}/address/list + defaults: { _controller: ChillPersonBundle:PersonAddress:list } + +chill_person_address_create: + path: /{_locale}/person/{person_id}/address/create + defaults: { _controller: ChillPersonBundle:PersonAddress:create } + methods: [POST] + +chill_person_address_new: + path: /{_locale}/person/{person_id}/address/new + defaults: { _controller: ChillPersonBundle:PersonAddress:new } + chill_person_address_edit: path: /{_locale}/person/{person_id}/address/{address_id}/edit defaults: { _controller: ChillPersonBundle:PersonAddress:edit } diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 959ec8db5..19b1be9ef 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -76,6 +76,12 @@ Since %date%: Depuis le %date% No address given: Pas d'adresse renseignée The address has been successfully updated: L'adresse a été mise à jour avec succès Update address for %name%: Mettre à jour une adresse pour %name% +Addresses'history for %name%: Historique des adresses de %name% +Addresses'history: Historique des adresses +New address for %name% : Nouvelle adresse pour %name% +The new address was created successfully: La nouvelle adresse a été créée +Add an address: Ajouter une adresse +Back to the person details: Retour aux détails de la personne #timeline 'An accompanying period is opened for %person% on %date%': Une période d'accompagnement a été ouverte le %date% pour %person% diff --git a/Resources/views/Address/edit.html.twig b/Resources/views/Address/edit.html.twig index b71134745..8090416aa 100644 --- a/Resources/views/Address/edit.html.twig +++ b/Resources/views/Address/edit.html.twig @@ -18,10 +18,12 @@ {% set activeRouteKey = '' %} -{% block title %}{{ 'Update address for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} +{% block title 'Update address for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) %} {% block personcontent %} +

{{ 'Update address for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}

+ {{ form_start(form) }} {{ form_row(form.streetAddress1) }} @@ -29,7 +31,16 @@ {{ form_row(form.postCode) }} {{ form_row(form.validFrom) }} - {{ form_row(form.submit, { 'attr' : { 'class': 'sc-button bt-edit' } } ) }} + {{ form_end(form) }} diff --git a/Resources/views/Address/list.html.twig b/Resources/views/Address/list.html.twig new file mode 100644 index 000000000..cc382514f --- /dev/null +++ b/Resources/views/Address/list.html.twig @@ -0,0 +1,84 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% import 'ChillMainBundle:Address:macro.html.twig' as address_macros %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'Addresses\'history for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}{% endblock %} + +{% block personcontent %} + +

{{ 'Addresses\'history for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}

+ + + + + + + + + + + {% if person.addresses|length == 0 %} + + + + {% else %} + {% for address in person.addresses %} + + + + + + + + {% endfor %} + {% endif %} + +
{{ 'Valid from'|trans }}{{ 'Address'|trans }} 
+ {{ 'No address given'|trans }} + + {{ 'Add an address'|trans }} + +
{{ 'Since %date%'|trans( { '%date%' : address.validFrom|localizeddate('long', 'none') } ) }} + {{ address_macros._render(address, { 'with_valid_from' : false } ) }} + + +
+ + + +{% endblock personcontent %} \ No newline at end of file diff --git a/Resources/views/Address/new.html.twig b/Resources/views/Address/new.html.twig new file mode 100644 index 000000000..8e9f9a4ca --- /dev/null +++ b/Resources/views/Address/new.html.twig @@ -0,0 +1,47 @@ +{# + * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +#} +{% extends "ChillPersonBundle::layout.html.twig" %} + +{% set activeRouteKey = '' %} + +{% block title %}{{ 'New address for %name%'|trans({ '%name%': person.firstName|capitalize ~ ' ' ~ person.lastName } )|capitalize }}{% endblock %} + +{% block personcontent %} + +

{{ 'New address for %name%'|trans({ '%name%': person.firstName ~ ' ' ~ person.lastName } ) }}

+ + {{ form_start(form) }} + + {{ form_row(form.streetAddress1) }} + {{ form_row(form.streetAddress2) }} + {{ form_row(form.postCode) }} + {{ form_row(form.validFrom) }} + + + + {{ form_end(form) }} + +{% endblock personcontent %} \ No newline at end of file diff --git a/Resources/views/Person/view.html.twig b/Resources/views/Person/view.html.twig index 97e1577c5..7290aedcc 100644 --- a/Resources/views/Person/view.html.twig +++ b/Resources/views/Person/view.html.twig @@ -175,9 +175,15 @@ This view should receive those arguments: {{ address._render(person.lastAddress) }} {{ 'Edit'|trans }} +
+ + {{ 'Addresses\'history'|trans }} {%- else -%} - {{ 'No address given'|trans }} + {{ 'No address given'|trans }} + + {{ 'Add an address'|trans }} + {%- endif -%} diff --git a/Tests/Controller/PersonAddressControllerTest.php b/Tests/Controller/PersonAddressControllerTest.php new file mode 100644 index 000000000..0f23236a8 --- /dev/null +++ b/Tests/Controller/PersonAddressControllerTest.php @@ -0,0 +1,189 @@ + + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +namespace Chill\PersonBundle\Tests\Controller; + +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Chill\PersonBundle\Entity\Person; + +/** + * + * + * @author Julien Fastré + */ +class PersonAddressControllerTest extends WebTestCase +{ + /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ + protected $em; + + /** @var Person The person on which the test is executed */ + protected static $person; + + /** + * + * @var \Chill\MainBundle\Entity\PostalCode + */ + protected $postalCode; + + /** + * + * @var \Symfony\Component\BrowserKit\Client + */ + protected $client; + + public static function setUpBeforeClass() + { + static::bootKernel(); + + $em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + $center = $em->getRepository('ChillMainBundle:Center') + ->findOneBy(array('name' => 'Center A')); + + self::$person = (new Person()) + ->setLastName("Tested person") + ->setFirstName("Test") + ->setCenter($center) + ->setGender(Person::MALE_GENDER); + + $em->persist(self::$person); + $em->flush(); + } + + /** + * Prepare client and create a random person + */ + public function setUp() + { + static::bootKernel(); + + $this->em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + $this->postalCode = $this->em->getRepository('ChillMainBundle:PostalCode') + ->findOneBy(array('code' => 1000)); + + $this->client = static::createClient(array(), array( + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + )); + } + + public static function tearDownAfter() + { + $this->refreshPerson(); + $this->em->remove(self::$person); + $this->em->flush(); + } + + /** + * Reload the person from the db + */ + protected function refreshPerson() + { + self::$person = $this->em->getRepository('ChillPersonBundle:Person') + ->find(self::$person->getId()); + } + + public function testEmptyList() + { + $crawler = $this->client->request('GET', '/fr/person/'. + self::$person->getId().'/address/list'); + + $this->assertTrue($this->client->getResponse()->isSuccessful()); + + $this->assertEquals(1, $crawler->filter('td:contains("Pas d\'adresse renseignée")') + ->count(), + "assert that a message say 'no address given'"); + + } + + /** + * @depends testEmptyList + */ + public function testCreateAddress() + { + $crawler = $this->client->request('GET', '/fr/person/'. + self::$person->getId().'/address/new'); + + $this->assertTrue($this->client->getResponse()->isSuccessful()); + + $form = $crawler->selectButton('Envoi')->form(array( + 'address[streetAddress1]' => 'Rue de la Paix, 50', + 'address[streetAddress2]' => $this->postalCode->getId(), + 'address[validFrom]' => '15-01-2016' + )); + + $this->client->submit($form); + + $crawler = $this->client->followRedirect(); + + $this->assertRegexp('|/fr/person/[0-9]{1,}/address/list|', + $this->client->getHistory()->current()->getUri(), + "assert that the current page is on |/fr/person/[0-9]{1,}/address/list|"); + $this->assertEquals(1, $crawler + ->filter('div.flash_message.success') + ->count(), + "Asserting that the response page contains a success flash message"); + $this->assertEquals(1, $crawler + ->filter('td:contains("Rue de la Paix, 50")') + ->count(), + "Asserting that the page contains the new address"); + + } + + /** + * @depends testCreateAddress + */ + public function testUpdateAddress() + { + $this->refreshPerson(); + $address = self::$person->getLastAddress(); + + $crawler = $this->client->request('GET', '/fr/person/'.self::$person->getId() + .'/address/'.$address->getId().'/edit'); + + $this->assertTrue($this->client->getResponse()->isSuccessful()); + + $form = $crawler->selectButton('Envoi')->form(array( + 'address[streetAddress1]' => 'Rue du Trou Normand, 15', + 'address[validFrom]' => '15-01-2015' + )); + + $this->client->submit($form); + + $crawler = $this->client->followRedirect(); + + $this->assertRegexp('|/fr/person/[0-9]{1,}/address/list|', + $this->client->getHistory()->current()->getUri(), + "assert that the current page is on |/fr/person/[0-9]{1,}/address/list|"); + $this->assertGreaterThan(0, $crawler + ->filter('div.flash_message.success') + ->count(), + "Asserting that the response page contains a success flash message"); + $this->assertEquals(1, $crawler + ->filter('td:contains("Rue du Trou Normand")') + ->count(), + "Asserting that the page contains the new address"); + } + + + +}