From afe6ace33187884fab7f3ff489e84a70cd7f5bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Thu, 10 Mar 2016 17:59:01 +0100 Subject: [PATCH] add a many-to-many relation to addresses --- DataFixtures/ORM/LoadPeople.php | 74 ++++++++++++++++++- DependencyInjection/Configuration.php | 1 + Entity/Person.php | 53 +++++++++++++ Resources/config/doctrine/Person.orm.yml | 5 ++ .../migrations/Version20160310161006.php | 49 ++++++++++++ Resources/translations/messages.fr.yml | 2 + Resources/views/Person/view.html.twig | 15 ++++ 7 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 Resources/migrations/Version20160310161006.php diff --git a/DataFixtures/ORM/LoadPeople.php b/DataFixtures/ORM/LoadPeople.php index fedff5a4d..63b0c53e5 100644 --- a/DataFixtures/ORM/LoadPeople.php +++ b/DataFixtures/ORM/LoadPeople.php @@ -26,6 +26,8 @@ use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Common\Persistence\ObjectManager; use Chill\PersonBundle\Entity\Person; use Symfony\Component\DependencyInjection\ContainerAwareInterface; +use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; +use Chill\MainBundle\Entity\Address; /** * Load people into database @@ -38,6 +40,13 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con use \Symfony\Component\DependencyInjection\ContainerAwareTrait; + protected $faker; + + public function __construct() + { + $this->faker = \Faker\Factory::create('fr_FR'); + } + public function prepare() { //prepare days, month, years @@ -114,12 +123,27 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $firstName = $this->firstNamesFemale[array_rand($this->firstNamesFemale)]; } + // add an address on 80% of the created people + if (rand(0,100) < 80) { + $address = $this->getRandomAddress(); + // on 30% of those person, add multiple addresses + if (rand(0,10) < 4) { + $address = array( + $address, + $this->getRandomAddress() + ); + } + } else { + $address = null; + } + $person = array( 'FirstName' => $firstName, 'LastName' => $lastName, 'Gender' => $sex, 'Nationality' => (rand(0,100) > 50) ? NULL: 'BE', 'center' => (rand(0,1) == 0) ? 'centerA': 'centerB', + 'Address' => $address, 'maritalStatus' => $this->maritalStatusRef[array_rand($this->maritalStatusRef)] ); @@ -142,10 +166,18 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con 'Email' => "Email d'un ami: roger@tt.com", 'CountryOfBirth' => 'BE', 'Nationality' => 'BE', - 'CFData' => array() + 'CFData' => array(), + 'Address' => null ), $specific); } + /** + * create a new person from array data + * + * @param array $person + * @param ObjectManager $manager + * @throws \Exception + */ private function addAPerson(array $person, ObjectManager $manager) { $p = new Person(); @@ -164,13 +196,51 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $value = $this->getReference($value); break; } - call_user_func(array($p, 'set'.$key), $value); + + //try to add the data using the setSomething function, + // if not possible, fallback to addSomething function + if (method_exists($p, 'set'.$key)) { + call_user_func(array($p, 'set'.$key), $value); + } elseif (method_exists($p, 'add'.$key)) { + // if we have a "addSomething", we may have multiple items to add + // so, we set the value in an array if it is not an array, and + // will call the function addSomething multiple times + if (!is_array($value)) { + $value = array($value); + } + + foreach($value as $v) { + if ($v !== NULL) { + call_user_func(array($p, 'add'.$key), $v); + } + } + + } } $manager->persist($p); echo "add person'".$p->__toString()."'\n"; } + /** + * Creata a random address + * + * @return Address + */ + private function getRandomAddress() + { + return (new Address()) + ->setStreetAddress1($this->faker->streetAddress) + ->setStreetAddress2( + rand(0,9) > 5 ? $this->faker->streetAddress : '' + ) + ->setPostcode($this->getReference( + LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)] + )) + ->setValidFrom($this->faker->dateTimeBetween('-5 years')) + ; + } + private function getCountry($countryCode) { if ($countryCode === NULL) { diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 5299a22fd..8a935b8b1 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -71,6 +71,7 @@ class Configuration implements ConfigurationInterface ->append($this->addFieldNode('country_of_birth')) ->append($this->addFieldNode('marital_status')) ->append($this->addFieldNode('spoken_languages')) + ->append($this->addFieldNode('address')) ->end() //children for 'person_fields', parent = array 'person_fields' ->end() // person_fields, parent = children of root ->end() // children of 'root', parent = root diff --git a/Entity/Person.php b/Entity/Person.php index 9f707790b..fda72bb54 100644 --- a/Entity/Person.php +++ b/Entity/Person.php @@ -27,6 +27,8 @@ use Chill\MainBundle\Entity\Country; use Chill\PersonBundle\Entity\MaritalStatus; use Doctrine\Common\Collections\ArrayCollection; use Chill\MainBundle\Entity\HasCenterInterface; +use Chill\MainBundle\Entity\Address; +use Doctrine\Common\Collections\Criteria; /** * Person @@ -100,9 +102,16 @@ class Person implements HasCenterInterface { /** @var array Array where customfield's data are stored */ private $cFData; + /** + * + * @var \Doctrine\Common\Collections\Collection + */ + private $addresses; + public function __construct(\DateTime $opening = null) { $this->accompanyingPeriods = new ArrayCollection(); $this->spokenLanguages = new ArrayCollection(); + $this->addresses = new ArrayCollection(); if ($opening === null) { $opening = new \DateTime(); @@ -597,6 +606,50 @@ class Person implements HasCenterInterface { return $this->spokenLanguages; } + public function addAddress(Address $address) + { + $this->addresses[] = $address; + + return $this; + } + + public function removeAddress(Address $address) + { + $this->addresses->removeElement($address); + } + + /** + * + * @return \Chill\MainBundle\Entity\Address[]@return Address[] + */ + public function getAddresses() + { + return $this->addresses; + } + + public function getLastAddress(\DateTime $date = null) + { + if ($date === null) { + $date = new \DateTime('now'); + } + + $lastAddress = null; + + foreach ($this->getAddresses() as $address) { + if ($address->getValidFrom() < $date) { + if ($lastAddress === NULL) { + $lastAddress = $address; + } else { + if ($lastAddress->getValidFrom() < $address->getValidFrom()) { + $lastAddress = $address; + } + } + } + } + + return $lastAddress; + } + /** * Validation callback that checks if the accompanying periods are valid * diff --git a/Resources/config/doctrine/Person.orm.yml b/Resources/config/doctrine/Person.orm.yml index 838ab1e8f..60f128a11 100644 --- a/Resources/config/doctrine/Person.orm.yml +++ b/Resources/config/doctrine/Person.orm.yml @@ -72,4 +72,9 @@ Chill\PersonBundle\Entity\Person: inverseJoinColumns: language_id: referencedColumnName: id + addresses: + targetEntity: Chill\MainBundle\Entity\Address + joinTable: + name: chill_person_persons_to_addresses + cascade: [persist, remove, merge, detach] lifecycleCallbacks: { } diff --git a/Resources/migrations/Version20160310161006.php b/Resources/migrations/Version20160310161006.php new file mode 100644 index 000000000..f17ae910c --- /dev/null +++ b/Resources/migrations/Version20160310161006.php @@ -0,0 +1,49 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE TABLE chill_person_persons_to_addresses (' + . 'person_id INT NOT NULL, ' + . 'address_id INT NOT NULL, ' + . 'PRIMARY KEY(person_id, address_id))'); + $this->addSql('CREATE INDEX IDX_4655A196217BBB47 ' + . 'ON chill_person_persons_to_addresses (person_id)'); + $this->addSql('CREATE INDEX IDX_4655A196F5B7AF75 ' + . 'ON chill_person_persons_to_addresses (address_id)'); + $this->addSql('ALTER TABLE chill_person_persons_to_addresses ' + . 'ADD CONSTRAINT FK_4655A196217BBB47 ' + . 'FOREIGN KEY (person_id) ' + . 'REFERENCES Person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_persons_to_addresses ' + . 'ADD CONSTRAINT FK_4655A196F5B7AF75 ' + . 'FOREIGN KEY (address_id) ' + . 'REFERENCES chill_main_address (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP TABLE chill_person_persons_to_addresses'); + + } +} diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 0aaccf0d0..9d7d9f364 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -70,6 +70,8 @@ Reset: 'Remise à zéro' 'Person details': 'Détails de la personne' 'Update details for %name%': 'Modifier détails de %name%' Accompanying period list: Périodes d'accompagnement +Since %date%: Depuis le %date% +No address given: Pas d'adresse renseignée #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/Person/view.html.twig b/Resources/views/Person/view.html.twig index e86a55857..1f17e7cb6 100644 --- a/Resources/views/Person/view.html.twig +++ b/Resources/views/Person/view.html.twig @@ -16,6 +16,8 @@ #} {% extends "ChillPersonBundle::layout.html.twig" %} +{% import 'ChillMainBundle:Address:macro.html.twig' as address %} + {% set activeRouteKey = 'chill_person_view' %} {# @@ -165,6 +167,19 @@ This view should receive those arguments:

 {{ 'Contact information'|trans|upper }}

+ {%- if chill_person.fields.address == 'visible' -%} +
+
{{ 'Address'|trans }}
+
+ {%- if person.lastAddress is not empty -%} + {{ address._render(person.lastAddress) }} + {%- else -%} + {{ 'No address given'|trans }} + {%- endif -%} +
+
+ {%- endif -%} + {%- if chill_person.fields.email == 'visible' -%}
{{ 'Email'|trans }} :