diff --git a/Controller/PersonController.php b/Controller/PersonController.php
index a0c0152f2..e536119d0 100644
--- a/Controller/PersonController.php
+++ b/Controller/PersonController.php
@@ -92,7 +92,10 @@ class PersonController extends Controller
if ($request->getMethod() === 'POST') {
$form->handleRequest($request);
- if ( ! $form->isValid() ) {
+ $errors = $this->get('validator')
+ ->validate($person, array('general'));
+
+ if ( count($errors) > 0 ) {
$errors = $form->getErrorsAsString();
diff --git a/Resources/translations/messages.en.yml b/Resources/translations/messages.en.yml
new file mode 100644
index 000000000..2a13e4c4e
--- /dev/null
+++ b/Resources/translations/messages.en.yml
@@ -0,0 +1,80 @@
+Edit: Edit
+'First name': First name
+'Last name': Last name
+Name: Name
+'Date of birth': Date of birth
+'Unknown date of birth': 'Date de naissance inconnue'
+Nationality: Nationality
+'Without nationality': 'Sans nationalité'
+Gender: Gender
+'Creation date': 'Date d''ouverture'
+'Not given': 'Non renseigné'
+'Place of birth': 'Place of birth'
+'Country of birth': 'Country of birth'
+'Unknown country of birth': 'Pays inconnu'
+'Marital status': 'État civil'
+'Number of children': 'Nombre d''enfants'
+'{0} No child|{1} One child | ]1,Inf] %nb% children': '{0} Aucun enfant|{1} Un enfant | ]1,Inf] %nb% enfants'
+'National number': 'Numéro national'
+Email: 'Email addresses'
+Address: Adresse
+Memo: Memo
+Phonenumber: 'Phonenumber7'
+'{0} Born the %date% | {1} Born the %date%': '{0} Né le %date% | {1} Née le %date%'
+'Spoken languages': 'Langues parlées'
+'Unknown spoken languages': 'Langues parlées inconnues'
+Male: Homme
+Female: Femme
+man: Homme
+woman: Femme
+Divorced: Divorcé(e)
+Separated: Séparé(e)
+Widow: Veuf(ve)
+'Unknow marital status': Indéterminé
+'Legal cohabitant': 'Cohabitant légal'
+Single: Célibataire
+Married: Marié(e)
+'General information': Généralités
+'Birth information': Naissance
+'Family information': Famille
+'Contact information': 'Informations de contact'
+'Administrative information': Administratif
+'Alreay existing person': 'Dossiers déjà encodés'
+'Add the person': 'Ajouter la personne'
+'Confirm the creation': 'Confirmer la création'
+'You will create this person': 'Vous allez créer le dossier suivant'
+Return: Retour
+Submit: Submit
+Reset: 'Remise à zéro'
+'The person data has been updated': 'Bravo ! Les données ont été mises à jour.'
+'{1} The person field %field% is incorrect. Please check. | ]1, Inf] Several person fields are incorrect. Please check.': '{1} Le champs %field% est incorrect. Veuillez le corriger. | ]1, Inf] Plusieurs champs sont incorrects. Veuillez les vérifier.'
+'Add a person': 'Ajout d''une personne'
+'Person Menu': 'Menu personne'
+'The person data are not valid': 'Les données de votre formulaire sont invalides.'
+'%nb% person with similar name. Please verify that this is a new person': '%nb% personnes ont un nom similaire. Vérifiez qu''il ne s''agit pas de l''une d''elles.'
+'The person has been created': 'Le dossier a été créé'
+'Person search results': 'Recherche de personnes'
+'Search within persons': 'Recherche parmi les personnes'
+'%total% persons matching the search %pattern%': '{0} Aucune personne ne correspond aux termes de recherche "%pattern%" | {1} Une personne a été trouvée par la recherche "%pattern%" | ]1,Inf] %total% personnes correspondent aux termes de recherche "%pattern%".'
+'Last opening since %last_opening%': 'Dernière ouverture le %last_opening%.'
+'Close person history': Clotûrer
+'Person history - %name%': 'Historique du dossier - %name%'
+'Opening date': 'Date d''ouverture'
+'Closing date': 'Date de fermeture'
+'Still open': 'Toujours en cours'
+'Close history': 'Clôre le dossier'
+'Open history': 'Ouvrir le dossier'
+'Create history': 'Nouvel ouverture-fermeture à une autre date'
+'Closing motive': 'Motif de clôture'
+'History created!': 'Bravo ! Le dossier est maintenant ouvert.'
+'Error! History not created!': 'Erreur ! Le dossier n''a pas pu être ouvert.'
+'Updating history done': 'Bravo ! La mise à jour de l''historique a réussi !'
+'Error when updating history': 'Les données introduites ne sont pas valides. Veuillez vérifier les informations ci-dessous.'
+'Beware history is closed': 'Attention le dossier est déjà fermé'
+'History closed!': 'Bravo ! Le dossier de %name% a été clotûré.'
+'Error! History not closed!': 'Les informations introduites ne sont pas valides. Le dossier n''a pu être clos.'
+'History closing form is not valide': 'Le formulaire n''est pas valide.'
+'Error! History %name% is not closed ; it can be open': 'Le dossier de %name% n''est pas fermé. Il ne peut donc être ouvert.'
+'History %name% opened!': 'Bravo ! Le dossier de %name a été ouvert'
+'History not opened': 'Les informations introduites ne sont pas valides. Le dossier n''a pu être ouvert.'
+'Person details': 'Détails de la personne'
diff --git a/Tests/Controller/PersonUpdateTest.php b/Tests/Controller/PersonUpdateTest.php
new file mode 100644
index 000000000..ec0228a6d
--- /dev/null
+++ b/Tests/Controller/PersonUpdateTest.php
@@ -0,0 +1,205 @@
+
+ *
+ * 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 Chill\PersonBundle\Entity\Person;
+use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
+
+/**
+ * Test the edition of persons
+ *
+ * As I am logged in as "center a_social"
+ *
+ * @author Julien Fastré
+ */
+class PersonUpdateTest extends WebTestCase
+{
+ /**
+ *
+ * @var \Doctrine\ORM\EntityManagerInterface
+ */
+ private $em;
+
+ /**
+ *
+ * @var Person
+ */
+ private $person;
+
+ /**
+ *
+ * @var string
+ */
+ private $editUrl;
+
+ /**
+ * prepare client and select a random person
+ */
+ public function setUp()
+ {
+ static::bootKernel();
+
+ $this->person = (new Person())
+ ->setLastName("My Beloved")
+ ->setFirstName("Jesus")
+ ->setGenre(Person::GENRE_MAN);
+
+ $this->em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager');
+
+ $this->em->persist($this->person);
+ $this->em->flush();
+
+ $this->editUrl = '/en/person/'.$this->person->getId().'/general/edit';
+ $this->seeUrl = '/en/person/'.$this->person->getId().'/general';
+
+ $this->client = static::createClient(array(), array(
+ 'PHP_AUTH_USER' => 'center a_social',
+ 'PHP_AUTH_PW' => 'password',
+ ));
+ }
+
+ /**
+ * Test the edit page exist and rendering is successful
+ */
+ public function testEditPageIsSuccessful()
+ {
+ $this->client->request('GET', $this->editUrl);
+
+ $this->assertTrue($this->client->getResponse()->isSuccessful(),
+ "The person edit form is accessible");
+ }
+
+ /**
+ * test the edition of a field
+ *
+ * Given I fill the field with $value
+ * And I submit the form
+ * Then I am redirected to the 'general' page
+ * And the person is updated in the db
+ *
+ * @dataProvider validTextFieldsProvider
+ * @param string $field
+ * @param string $value
+ * @param \Closure $callback
+ */
+ public function testEditTextField($field, $value, \Closure $callback)
+ {
+ $crawler = $this->client->request('GET', $this->editUrl);
+
+ $form = $crawler->selectButton('Submit')
+ ->form();
+ //transform countries into value if needed
+ switch ($field) {
+ case 'nationality':
+ case 'countryOfBirth':
+ if ($value !== NULL) {
+ $country = $this->em->getRepository('ChillMainBundle:Country')
+ ->findOneByCountryCode($value);
+ $transformedValue = $country->getId();
+ } else {
+ $transformedValue = NULL;
+ }
+ break;
+ default:
+ $transformedValue = $value;
+ }
+
+ $form->get('chill_personbundle_person['.$field. ']')
+ ->setValue($transformedValue);
+
+ $this->client->submit($form);
+ $this->em->refresh($this->person);
+
+ $this->assertTrue($this->client->getResponse()->isRedirect($this->seeUrl));
+ $this->assertEquals($value, $callback($this->person));
+ }
+
+ /**
+ * provide valid values to test, with field name and
+ * a function to find the value back from person entity
+ *
+ * @return mixed[]
+ */
+ public function validTextFieldsProvider()
+ {
+ return array(
+ ['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ],
+ ['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ],
+ ['placeOfBirth', 'none place', function(Person $person) { return $person->getPlaceOfBirth(); }],
+ ['dateOfBirth', '15-12-1980', function(Person $person) { return $person->getDateOfBirth()->format('d-m-Y'); }],
+ ['phonenumber', '0123456789', function(Person $person) { return $person->getPhonenumber(); }],
+ ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }],
+ ['countryOfBirth', 'BE', function(Person $person) { return $person->getCountryOfBirth()->getCountryCode(); }],
+ ['nationality', 'FR', function(Person $person) { return $person->getNationality()->getCountryCode(); }],
+ ['placeOfBirth', '', function(Person $person) { return $person->getPlaceOfBirth(); }],
+ ['dateOfBirth', '', function(Person $person) { return $person->getDateOfBirth(); }],
+ ['phonenumber', '', function(Person $person) { return $person->getPhonenumber(); }],
+ ['memo', '', function(Person $person) { return $person->getMemo(); }],
+ ['countryOfBirth', NULL, function(Person $person) { return $person->getCountryOfBirth(); }],
+ ['nationality', NULL, function(Person $person) { return $person->getNationality(); }],
+ ['genre', Person::GENRE_WOMAN, function(Person $person) { return $person->getGenre(); }]
+ );
+ }
+
+ /**
+ *
+ * @dataProvider providesInvalidFieldsValues
+ * @param string $field
+ * @param string $value
+ */
+ public function testInvalidFields($field, $value)
+ {
+ $crawler = $this->client->request('GET', $this->editUrl);
+
+ $form = $crawler->selectButton('Submit')
+ ->form();
+ $form->get('chill_personbundle_person['.$field.']')
+ ->setValue($value);
+
+ $crawler = $this->client->submit($form);
+
+ $this->assertFalse($this->client->getResponse()->isRedirect());
+ $this->assertGreaterThan(0, $crawler->filter('.error')->count());
+ }
+
+ public function providesInvalidFieldsValues()
+ {
+ return array(
+ ['firstName', $this->getVeryLongText()],
+ ['lastName', $this->getVeryLongText()],
+ ['firstName', ''],
+ ['lastName', '']
+ );
+ }
+
+ public function tearDown()
+ {
+ $this->em->remove($this->person);
+ $this->em->flush();
+ }
+
+ private function getVeryLongText()
+ {
+ return <<