From c60d6acf9764aef5224ac318440e86e790fc6771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 22 Feb 2016 14:48:35 +0100 Subject: [PATCH] An activity may have multiple reasons The relationship between Activity and Reasons is now many-to-many. Some improvement in show activity layout. refs #4 #7 --- DataFixtures/ORM/LoadActivity.php | 17 +++- Entity/Activity.php | 29 ++++--- Form/ActivityType.php | 5 +- Resources/config/doctrine/Activity.orm.yml | 5 +- .../migrations/Version20160222103457.php | 79 +++++++++++++++++++ Resources/translations/messages.fr.yml | 4 +- Resources/views/Activity/edit.html.twig | 13 ++- Resources/views/Activity/list.html.twig | 26 ++++-- Resources/views/Activity/show.html.twig | 39 ++++++--- .../views/ActivityReason/macro.html.twig | 3 + Tests/Controller/ActivityControllerTest.php | 16 +++- 11 files changed, 197 insertions(+), 39 deletions(-) create mode 100644 Resources/migrations/Version20160222103457.php create mode 100644 Resources/views/ActivityReason/macro.html.twig diff --git a/DataFixtures/ORM/LoadActivity.php b/DataFixtures/ORM/LoadActivity.php index fe14fd86c..ce1be9ceb 100644 --- a/DataFixtures/ORM/LoadActivity.php +++ b/DataFixtures/ORM/LoadActivity.php @@ -84,9 +84,15 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C * * @return \Chill\ActivityBundle\Entity\ActivityReason */ - private function getRandomActivityReason() + private function getRandomActivityReason(array $excludingIds) { $reasonRef = LoadActivityReason::$references[array_rand(LoadActivityReason::$references)]; + + if (in_array($this->getReference($reasonRef)->getId(), $excludingIds)) { + // we have a reason which should be excluded. Find another... + return $this->getRandomActivityReason($excludingIds); + } + return $this->getReference($reasonRef); } @@ -109,10 +115,17 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C ->setDate($this->faker->dateTimeThisYear()) ->setDurationTime($this->faker->dateTime(36000)) ->setType($this->getRandomActivityType()) - ->setReason($this->getRandomActivityReason()) ->setScope($this->getRandomScope()) ->setAttendee($this->faker->boolean()) ->setRemark('A remark'); + + $usedId = array(); + for ($i = 0; $i < rand(0, 4); $i++) { + $reason = $this->getRandomActivityReason($usedId); + $usedId[] = $reason->getId(); + $activity->addReason($reason); + } + return $activity; } diff --git a/Entity/Activity.php b/Entity/Activity.php index e7ca954a7..954ae7e34 100644 --- a/Entity/Activity.php +++ b/Entity/Activity.php @@ -27,6 +27,7 @@ use Chill\ActivityBundle\Entity\ActivityType; use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; +use Doctrine\Common\Collections\ArrayCollection; /** * Activity @@ -64,9 +65,9 @@ class Activity implements HasCenterInterface, HasScopeInterface private $attendee; /** - * @var ActivityReason + * @var \Doctrine\Common\Collections\Collection */ - private $reason; + private $reasons; /** * @var ActivityType @@ -82,6 +83,11 @@ class Activity implements HasCenterInterface, HasScopeInterface * @var Person */ private $person; + + public function __construct() + { + $this->reasons = new ArrayCollection(); + } /** @@ -215,27 +221,32 @@ class Activity implements HasCenterInterface, HasScopeInterface } /** - * Set reason + * Add a reason * * @param ActivityReason $reason * * @return Activity */ - public function setReason(ActivityReason $reason) + public function addReason(ActivityReason $reason) { - $this->reason = $reason; + $this->reasons[] = $reason; return $this; } + + public function removeReason(ActivityReason $reason) + { + $this->reasons->removeElement($reason); + } /** - * Get reason + * Get reasons * - * @return ActivityReason + * @return \Doctrine\Common\Collections\Collection */ - public function getReason() + public function getReasons() { - return $this->reason; + return $this->reasons; } /** diff --git a/Form/ActivityType.php b/Form/ActivityType.php index b6c52fb4a..1c9580cb4 100644 --- a/Form/ActivityType.php +++ b/Form/ActivityType.php @@ -85,7 +85,10 @@ class ActivityType extends AbstractType )) ->add('user') ->add('scope') - ->add('reason', 'translatable_activity_reason') + ->add('reasons', 'translatable_activity_reason', array( + 'multiple' => true, + 'required' => false + )) ->add('type', 'translatable_activity_type') //->add('person') ; diff --git a/Resources/config/doctrine/Activity.orm.yml b/Resources/config/doctrine/Activity.orm.yml index 22ebc3219..bed936936 100644 --- a/Resources/config/doctrine/Activity.orm.yml +++ b/Resources/config/doctrine/Activity.orm.yml @@ -16,13 +16,14 @@ Chill\ActivityBundle\Entity\Activity: type: text attendee: type: boolean + manyToMany: + reasons: + targetEntity: Chill\ActivityBundle\Entity\ActivityReason manyToOne: user: targetEntity: Chill\MainBundle\Entity\User scope: targetEntity: Chill\MainBundle\Entity\Scope - reason: - targetEntity: Chill\ActivityBundle\Entity\ActivityReason type: targetEntity: Chill\ActivityBundle\Entity\ActivityType person: diff --git a/Resources/migrations/Version20160222103457.php b/Resources/migrations/Version20160222103457.php new file mode 100644 index 000000000..c08be5c2f --- /dev/null +++ b/Resources/migrations/Version20160222103457.php @@ -0,0 +1,79 @@ +abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.'); + + // create the new table activity reason + $this->addSql('CREATE TABLE activity_activityreason (' + . 'activity_id INT NOT NULL, ' + . 'activityreason_id INT NOT NULL, ' + . 'PRIMARY KEY(activity_id, activityreason_id))' + ); + $this->addSql('CREATE INDEX IDX_338A864381C06096 ON activity_activityreason (activity_id)'); + $this->addSql('CREATE INDEX IDX_338A8643D771E0FC ON activity_activityreason (activityreason_id)'); + $this->addSql('ALTER TABLE activity_activityreason ' + . 'ADD CONSTRAINT FK_338A864381C06096 FOREIGN KEY (activity_id) ' + . 'REFERENCES Activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_activityreason ' + . 'ADD CONSTRAINT FK_338A8643D771E0FC FOREIGN KEY (activityreason_id) ' + . 'REFERENCES ActivityReason (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + + // migrate old data to new table + $this->addSql('INSERT INTO activity_activityreason (activity_id, activityreason_id) ' + . 'SELECT id, reason_id FROM activity WHERE reason_id IS NOT NULL'); + + + // remove old column + $this->addSql('ALTER TABLE activity DROP CONSTRAINT fk_55026b0c59bb1592'); + $this->addSql('DROP INDEX idx_55026b0c59bb1592'); + $this->addSql('ALTER TABLE activity DROP reason_id'); + } + + /** + * @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('ALTER TABLE Activity ADD reason_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE Activity ADD CONSTRAINT ' + . 'fk_55026b0c59bb1592 FOREIGN KEY (reason_id) ' + . 'REFERENCES activityreason (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX idx_55026b0c59bb1592 ON Activity (reason_id)'); + + // try to keep at least on activity reason... + $this->addSql('UPDATE activity + SET reason_id=rid + FROM ( + SELECT activity_id AS aid, MIN(activityreason_id) AS rid + FROM activity_activityreason + GROUP BY activity_id ) AS sb + WHERE sb.aid = activity.id' + ); + + + $this->addSql('DROP TABLE activity_activityreason'); + + } +} diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml index 0d4086327..387159c9e 100644 --- a/Resources/translations/messages.fr.yml +++ b/Resources/translations/messages.fr.yml @@ -4,7 +4,7 @@ Edit the activity: Modifier l'activité Activity: Activité Duration time: Durée Duration Time: Durée -Reason: Sujet +Reasons: Sujets Attendee: Présence de la personne Remark: Notes Add a new activity: Ajouter une nouvelle activité @@ -15,6 +15,8 @@ Delete: Supprimer Update: Mettre à jour Update activity: Édition de l'activité Scope: Cercle +Activity data: Données de l'activité +No reason associated: Aucun sujet #forms Activity creation: Nouvelle activité diff --git a/Resources/views/Activity/edit.html.twig b/Resources/views/Activity/edit.html.twig index d92ecab39..456bb3221 100644 --- a/Resources/views/Activity/edit.html.twig +++ b/Resources/views/Activity/edit.html.twig @@ -18,12 +18,23 @@ {% set activeRouteKey = 'chill_activity_activity_list' %} -{% block title %}{{ 'Activity edit' |trans }}{% endblock title %} +{% block title 'Update activity'|trans %} {% block personcontent %}

{{ "Update activity"|trans }}

{{ form_start(edit_form) }} + + {{ form_row(edit_form.user) }} + {{ form_row(edit_form.scope) }} + +

{{ 'Activity data'|trans }}

+ {{ form_row(edit_form.date) }} + {{ form_row(edit_form.durationTime) }} + {{ form_row(edit_form.remark) }} + {{ form_row(edit_form.attendee) }} + {{ form_row(edit_form.reasons) }} + {{ form_row(edit_form.type) }} {{ form_widget(edit_form) }}
diff --git a/Resources/views/Activity/list.html.twig b/Resources/views/Activity/list.html.twig index 9bed49ec5..cfaf9cf89 100644 --- a/Resources/views/Activity/list.html.twig +++ b/Resources/views/Activity/list.html.twig @@ -16,6 +16,8 @@ #} {% extends "ChillPersonBundle::layout.html.twig" %} +{% import 'ChillActivityBundle:ActivityReason:macro.html.twig' as m %} + {% set activeRouteKey = 'chill_activity_activity_list' %} {% block title %}{{ 'Activity list' |trans }}{% endblock title %} @@ -26,10 +28,9 @@ {{'Date' | trans }} {{'Duration Time' | trans }} - {{'Reason' | trans}} + {{'Reasons' | trans}} {{'Type' | trans}} - - +   @@ -37,13 +38,22 @@ {% if activity.date %}{{ activity.date|localizeddate('long', 'none') }}{% endif %} {{ activity.durationTime|date('H:i') }} - {{ activity.reason.name | localize_translatable_string }} + + {%- if activity.reasons is empty -%} + {{ 'No reason associated'|trans }} + {%- else -%} + {% for r in activity.reasons %}{{ m.reason(r) }} {% endfor %} + {%- endif -%} + {{ activity.type.name | localize_translatable_string }} - {{ 'Show' | trans }} - - - {{ 'Edit' | trans }} +