diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c2a13ec3..518fcabb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to +* [person]: Add civility to the person +* [person]: Various improvements on the edit person form +* [person]: Set available_languages and available_countries as parameters for use in the edit person form +* [activity] Bugfix: documents can now be added to an activity. * [tasks] improve tasks with filter order * [tasks] refactor singleControllerTasks: limit the number of conditions from the context * [validations] validation of accompanying period added: no duplicate participations or resources (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/60). @@ -22,9 +26,21 @@ and this project adheres to * [activity]: perform client-side validation & show/hide fields in the "new location" modal * [docstore] voter for PersonDocument and AccompanyingCourseDocument on the 2.0 way (using VoterHelperFactory) * [docstore] add authorization check inside controller and menu +* [activity]: fix inheritance for role `ACTIVITY FULL` and add missing acl in menu +* [person] show current address in search results +* [person] show alt names in search results +* [admin]: links to activity admin section added again. +* [household]: endDate field deleted from household edit form. +* [household]: View accompanying periods of current and old household members. +* [tasks]: different layout for task list / my tasks, and fix link to tasks in alert or in warning +* [admin]: links to activity admin section added again. +* [household]: household addresses ordered by ValidFrom date and by id to show the last created address on top. +* [socialWorkAction]: display of social issue and parent issues + banner context added. +* [DBAL dependencies] Upgrade to DBAL 3.1 ## Test releases + ### Test release 2021-10-27 * [person]: delete double actions buttons on search person page diff --git a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php index a6f1d6a8a..f4aeba174 100644 --- a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php +++ b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php @@ -87,7 +87,9 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf ActivityVoter::UPDATE => array(ActivityVoter::SEE_DETAILS), ActivityVoter::CREATE => array(ActivityVoter::SEE_DETAILS), ActivityVoter::DELETE => array(ActivityVoter::SEE_DETAILS), - ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE) + ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE), + ActivityVoter::FULL => [ActivityVoter::CREATE, ActivityVoter::DELETE, + ActivityVoter::UPDATE], ) )); } diff --git a/src/Bundle/ChillActivityBundle/Entity/Activity.php b/src/Bundle/ChillActivityBundle/Entity/Activity.php index ae310f775..e25448f10 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -158,7 +158,7 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer private ?Collection $thirdParties = null; /** - * @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject") + * @ORM\ManyToMany(targetEntity="Chill\DocStoreBundle\Entity\StoredObject", cascade={"persist"}) */ private Collection $documents; diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php b/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php index 6116815dc..b22dd5281 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php @@ -1,19 +1,19 @@ - * + * * 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 . */ @@ -44,7 +44,7 @@ class ActivityReason /** * @var array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -108,7 +108,7 @@ class ActivityReason return $this->name; } } - + /** * Set category of the reason. If you set to the reason an inactive * category, the reason will become inactive @@ -121,7 +121,7 @@ class ActivityReason if($this->category !== $category && ! $category->getActive()) { $this->setActive(False); } - + $this->category = $category; return $this; diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php index dc5d5f9ba..b7afbcb1c 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php @@ -2,17 +2,17 @@ /* * Copyright (C) 2015, 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 . */ @@ -43,7 +43,7 @@ class ActivityReasonCategory /** * @var string - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -52,7 +52,7 @@ class ActivityReasonCategory * @ORM\Column(type="boolean") */ private $active = true; - + /** * Array of ActivityReason * @var ArrayCollection @@ -61,7 +61,7 @@ class ActivityReasonCategory * mappedBy="category") */ private $reasons; - + /** * ActivityReasonCategory constructor. */ @@ -69,7 +69,7 @@ class ActivityReasonCategory { $this->reasons = new ArrayCollection(); } - + /** * @return string */ @@ -139,9 +139,9 @@ class ActivityReasonCategory $reason->setActive($active); } } - + $this->active = $active; - + return $this; } diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index 14ede1335..c8ae6ca07 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -44,7 +44,7 @@ class ActivityType private ?int $id; /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private array $name = []; diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php index 2da799980..a95424312 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php @@ -40,7 +40,7 @@ class ActivityTypeCategory private ?int $id; /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private array $name = []; diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php index f21184a30..fa4b23212 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php @@ -71,7 +71,7 @@ class TranslatableActivityType extends AbstractType if ($options['active_only'] === true) { $qb->where($qb->expr()->eq('at.active', ':active')); - $qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN); + $qb->setParameter('active', true, \Doctrine\DBAL\Types\Types::BOOLEAN); } } diff --git a/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php index 7d5ba520d..b8ea9bf9a 100644 --- a/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -2,29 +2,27 @@ namespace Chill\ActivityBundle\Menu; +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface { - protected TokenStorageInterface $tokenStorage; - - protected AuthorizationHelper $authorizationHelper; - protected TranslatorInterface $translator; + protected Security $security; + public function __construct( - TokenStorageInterface $tokenStorage, - AuthorizationHelper $authorizationHelper, + Security $security, TranslatorInterface $translator ) { + $this->security = $security; $this->translator = $translator; - $this->authorizationHelper = $authorizationHelper; - $this->tokenStorage = $tokenStorage; } public static function getMenuIds(): array { @@ -35,7 +33,8 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface { $period = $parameters['accompanyingCourse']; - if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep()) { + if (AccompanyingPeriod::STEP_DRAFT !== $period->getStep() + && $this->security->isGranted(ActivityVoter::SEE, $period)) { $menu->addChild($this->translator->trans('Activity'), [ 'route' => 'chill_activity_activity_list', 'routeParameters' => [ diff --git a/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php new file mode 100644 index 000000000..ce7618b6d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Menu/AdminMenuBuilder.php @@ -0,0 +1,48 @@ +security = $security; + } + + public static function getMenuIds(): array + { + return ['admin_index', 'admin_section', 'admin_activity']; + } + + public function buildMenu($menuId, MenuItem $menu, array $parameters) + { + if (!$this->security->isGranted('ROLE_ADMIN')) { + return; + } + + if (in_array($menuId, ['admin_index', 'admin_section'])) { + $menu->addChild('Activities', [ + 'route' => 'chill_admin_activity_index' + ]) + ->setExtras([ + 'order' => 2000, + 'explain' => "Activity configuration" + ]); + } else { + $menu + ->addChild('Activities', [ + 'route' => 'chill_admin_activity_index' + ]) + ->setExtras([ + 'order' => '60' + ]); + } + } +} \ No newline at end of file diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php b/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php index 4419c3699..5adf42e23 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php @@ -4,7 +4,7 @@ namespace Chill\Migrations\Activity; use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; /** * Add an "active" column on activitytype table diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php index 43f8c8460..283a4f077 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210401090853.php @@ -22,7 +22,6 @@ final class Version20210401090853 extends AbstractMigration // this up() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SEQUENCE activitytypecategory_id_seq INCREMENT BY 1 MINVALUE 1 START 1000'); $this->addSql('CREATE TABLE activitytypecategory (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id))'); - $this->addSql('COMMENT ON COLUMN activitytypecategory.name IS \'(DC2Type:json_array)\''); $this->addSql('INSERT INTO activitytypecategory VALUES(1, \'{"fr": "Défaut", "en": "Default"}\', true)'); } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php index 53a5219bd..c5f3f7d8d 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210408122329.php @@ -51,7 +51,6 @@ final class Version20210408122329 extends AbstractMigration $this->addSql('ALTER TABLE activitytype ADD socialDataLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); $this->addSql('ALTER TABLE activitytype ALTER name SET NOT NULL'); $this->addSql('ALTER TABLE activitytype ALTER active DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN activitytype.name IS \'(DC2Type:json_array)\''); } public function down(Schema $schema) : void diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 55e55d370..d0c3ddc6d 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -99,10 +99,13 @@ CHILL_ACTIVITY_LIST: Liste des activités Activities: Activités Activity configuration: Configuration des activités Activity configuration menu: Configuration des activités -Activity Types: Types d'activité +Activity types: Types d'activité +Activity type configuration: Configuration des categories d'activités Activity Reasons: Sujets d'une activité Activity Reasons Category: Catégories de sujet d'activités Activity Types Categories: Catégories des types d'activité +Activity Presences: Presences des activités + # Crud crud: diff --git a/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php b/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php index ecc1a1f90..24fc89162 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Menu/AdminMenuBuilder.php @@ -32,7 +32,7 @@ final class AdminMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuild ]) ->setExtras([ 'order' => 900, - 'explain' => "Configure aside activities categories" + 'explain' => "Aside activity type configuration" ]); } else { $menu diff --git a/src/Bundle/ChillAsideActivityBundle/src/Resources/views/asideActivityCategory/index.html.twig b/src/Bundle/ChillAsideActivityBundle/src/Resources/views/asideActivityCategory/index.html.twig index 2c8373daf..00dc1d3ea 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Resources/views/asideActivityCategory/index.html.twig +++ b/src/Bundle/ChillAsideActivityBundle/src/Resources/views/asideActivityCategory/index.html.twig @@ -1,7 +1,7 @@ {% extends "@ChillAsideActivity/Admin/layout_asideactivity.html.twig" %} {% block admin_content %} -

{{ 'Aside Activity Type list'|trans }}

+

{{ 'Aside Activity Type List'|trans }}

diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml index dac2430bd..6d219626d 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml @@ -3,6 +3,7 @@ Show the aside activity: Voir l'activité annexe Edit the aside activity: Modifier l'activité annexe Remove aside activity: Supprimer l'activité annexe Aside activity: Activité annexe +Aside Activity Type List: Liste des catégories d'activités annexes Duration time: Durée durationTime: durée user_username: nom de l'utilisateur @@ -156,6 +157,11 @@ The activity has been successfully removed.: L'activité a été supprimée. #Menu Create an aside activity: "Créer une activité annexe" +Aside activity categories: Catégories des activités annexes Aside activity configuration menu: "Menu de configuration des activités annexes" -Aside activity configuration: "Configuration des activités annexes" Phonecall: "Appel téléphonique" + +# admin +Aside activities: Activités annexes +Aside activity types: Types d'activités annexes +Aside activity type configuration: Configuration des categories d'activités annexes diff --git a/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php b/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php index ce3d1f6e4..bca569a49 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php +++ b/src/Bundle/ChillCalendarBundle/Entity/CancelReason.php @@ -34,7 +34,7 @@ class CancelReason private $canceledBy; /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name = []; diff --git a/src/Bundle/ChillCalendarBundle/Entity/Invite.php b/src/Bundle/ChillCalendarBundle/Entity/Invite.php index 5baca36ab..c1e7f8b57 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/Invite.php +++ b/src/Bundle/ChillCalendarBundle/Entity/Invite.php @@ -25,7 +25,7 @@ class Invite private User $user; /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private array $status = []; diff --git a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php index 7eb161a50..9a3c8ce56 100644 --- a/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillCalendarBundle/Menu/UserMenuBuilder.php @@ -73,19 +73,14 @@ class UserMenuBuilder implements LocalMenuBuilderInterface { $user = $this->tokenStorage->getToken()->getUser(); - if ($this->authorizationChecker->isGranted('ROLE_USER') - && $user instanceof User - ) { - $menu->addChild("My calendar list", [ - 'route' => 'chill_calendar_calendar_list', - 'routeParameters' => [ - 'user_id' => $user->getId(), - ] - ]) - ->setExtras([ - 'order' => 9, - 'icon' => 'tasks' - ]); + if ($this->authorizationChecker->isGranted('ROLE_USER')){ + $menu->addChild("My calendar list", [ + 'route' => 'chill_calendar_calendar_list' + ]) + ->setExtras([ + 'order' => 9, + 'icon' => 'tasks' + ]); } } diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php index 7e535fe27..0d2dd2f2e 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210715141731.php @@ -50,10 +50,7 @@ final class Version20210715141731 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.startDate IS \'(DC2Type:date_immutable)\''); $this->addSql('COMMENT ON COLUMN chill_calendar.calendar_range.endDate IS \'(DC2Type:date_immutable)\''); $this->addSql('CREATE TABLE chill_calendar.cancel_reason (id INT NOT NULL, active BOOLEAN NOT NULL, canceledBy JSON NOT NULL, name JSON NOT NULL, PRIMARY KEY(id))'); - $this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.name IS \'(DC2Type:json_array)\''); - $this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.canceledBy IS \'(DC2Type:json_array)\''); $this->addSql('CREATE TABLE chill_calendar.invite (id INT NOT NULL, user_id INT DEFAULT NULL, status JSON NOT NULL, PRIMARY KEY(id))'); - $this->addSql('COMMENT ON COLUMN chill_calendar.invite.status IS \'(DC2Type:json_array)\''); $this->addSql('CREATE INDEX IDX_F517FFA7A76ED395 ON chill_calendar.invite (user_id)'); $this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315ACA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_calendar.calendar ADD CONSTRAINT FK_712315ACD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); @@ -74,7 +71,7 @@ final class Version20210715141731 extends AbstractMigration } public function down(Schema $schema): void - { + { $this->addSql('ALTER TABLE chill_calendar.calendar_to_persons DROP CONSTRAINT FK_AEE94715A40A2C8'); $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals DROP CONSTRAINT FK_FADF2C77A40A2C8'); $this->addSql('ALTER TABLE chill_calendar.calendar_to_thirdparties DROP CONSTRAINT FK_2BAB7EFDA40A2C8'); diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php b/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php index 3f85968c4..b90c4b1b5 100644 --- a/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20210723074557.php @@ -34,6 +34,5 @@ final class Version20210723074557 extends AbstractMigration $this->addSql('ALTER TABLE chill_calendar.calendar_to_non_professionals ADD CONSTRAINT fk_fadf2c77217bbb47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy TYPE JSON'); $this->addSql('ALTER TABLE chill_calendar.cancel_reason ALTER canceledBy DROP DEFAULT'); - $this->addSql('COMMENT ON COLUMN chill_calendar.cancel_reason.canceledby IS \'(DC2Type:json_array)\''); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php index d7fb1e769..8472896eb 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php @@ -40,7 +40,7 @@ class CustomField * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + /** * @var string * @@ -61,18 +61,18 @@ class CustomField * @ORM\Column(type="boolean") */ private $active = true; - + /** * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $options = array(); - + /** * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -82,14 +82,14 @@ class CustomField * @ORM\Column(type="float") */ private $ordering; - + /** * @var boolean * * @ORM\Column(type="boolean") */ private $required = FALSE; - + const ONE_TO_ONE = 1; const ONE_TO_MANY = 2; @@ -102,7 +102,7 @@ class CustomField */ private $customFieldGroup; - + /** * Get id * @@ -112,7 +112,7 @@ class CustomField { return $this->id; } - + /** * @return string */ @@ -120,15 +120,15 @@ class CustomField { return $this->slug; } - + /** * @return array */ function getOptions() { return $this->options; - } - + } + /** * Set type * @@ -152,7 +152,7 @@ class CustomField return $this->type; } - + /** * Set active * @@ -229,9 +229,9 @@ class CustomField } } } - + return ''; - + } else { return $this->name; }; @@ -272,7 +272,7 @@ class CustomField return $this; } - + /** * @param $slug * @return $this @@ -282,20 +282,20 @@ class CustomField $this->slug = $slug; return $this; } - + /** * alias for isRequired - * + * * @return boolean */ public function getRequired() { return $this->isRequired(); } - + /** * return true if the field required - * + * * @return boolean */ public function isRequired() @@ -308,5 +308,5 @@ class CustomField $this->required = $required; return $this; } - + } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php index 06174a9a6..ee3eae24f 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php @@ -39,21 +39,21 @@ class Option * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + /** * @var string * @ORM\Column(type="string", length=15) */ private $key; - + /** * A json representation of text (multilingual) * * @var array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $text; - + /** * @var Collection * @ORM\OneToMany( @@ -61,7 +61,7 @@ class Option * mappedBy="parent") */ private $children; - + /** * @var Option * @ORM\ManyToOne( @@ -70,19 +70,19 @@ class Option * @ORM\JoinColumn(nullable=true) */ private $parent; - + /** * @var string * @ORM\Column(type="string", length=50, name="internal_key") */ private $internalKey = ''; - + /** * @var boolean * @ORM\Column(type="boolean") */ private $active = true; - + /** * @return int */ @@ -90,7 +90,7 @@ class Option { return $this->id; } - + /** * @return string */ @@ -98,7 +98,7 @@ class Option { return $this->key; } - + /** * @return array */ @@ -106,7 +106,7 @@ class Option { return $this->text; } - + /** * @return Collection */ @@ -114,7 +114,7 @@ class Option { return $this->children; } - + /** * @return Option */ @@ -122,7 +122,7 @@ class Option { return $this->parent; } - + /** * @param $key * @return $this @@ -132,7 +132,7 @@ class Option $this->key = $key; return $this; } - + /** * @param array $text * @return $this @@ -142,7 +142,7 @@ class Option $this->text = $text; return $this; } - + /** * @param Option|null $parent * @return $this @@ -153,16 +153,16 @@ class Option $this->key = $parent->getKey(); return $this; } - + /** - * + * * @return boolean */ public function hasParent() { return $this->parent === NULL ? false : true; } - + /** * @return string */ @@ -170,7 +170,7 @@ class Option { return $this->internalKey; } - + /** * @return bool */ @@ -178,7 +178,7 @@ class Option { return $this->active; } - + /** * @return bool */ @@ -186,7 +186,7 @@ class Option { return $this->isActive(); } - + /** * @param $internal_key * @return $this @@ -196,7 +196,7 @@ class Option $this->internalKey = $internal_key; return $this; } - + /** * @param $active * @return $this @@ -206,5 +206,5 @@ class Option $this->active = $active; return $this; } - + } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php index f9bb90d6d..db484b9de 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php @@ -45,7 +45,7 @@ class CustomFieldsGroup /** * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -76,15 +76,15 @@ class CustomFieldsGroup * @var array|null */ private $activeCustomFields = null; - + /** * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $options = array(); - - + + /** * CustomFieldsGroup constructor. */ @@ -115,7 +115,7 @@ class CustomFieldsGroup { $this->customFields->removeElement($customField); } - + /** * @return Collection */ @@ -142,7 +142,7 @@ class CustomFieldsGroup return $this->activeCustomFields; } - + /** * Get id * @@ -184,9 +184,9 @@ class CustomFieldsGroup } } } - + return ''; - + } else { return $this->name; } @@ -214,10 +214,10 @@ class CustomFieldsGroup { return $this->entity; } - + /** * get options array - * + * * @return array */ public function getOptions() @@ -227,7 +227,7 @@ class CustomFieldsGroup /** * set options array - * + * * @param array $options * @return CustomFieldsGroup */ diff --git a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php index ad8d62056..c61256e8b 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php +++ b/src/Bundle/ChillDocGeneratorBundle/Entity/DocGeneratorTemplate.php @@ -21,7 +21,7 @@ class DocGeneratorTemplate private int $id; /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") * @Serializer\Groups({"read"}) */ private array $name = []; diff --git a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php index c055bf428..363c94938 100644 --- a/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php +++ b/src/Bundle/ChillDocGeneratorBundle/migrations/Version20210812214310.php @@ -22,7 +22,6 @@ final class Version20210812214310 extends AbstractMigration $this->addSql('ALTER TABLE chill_docgen_template ADD entities TEXT'); $this->addSql('ALTER TABLE chill_docgen_template ADD context VARCHAR(255)'); $this->addSql('COMMENT ON COLUMN chill_docgen_template.entities IS \'(DC2Type:simple_array)\''); - $this->addSql('COMMENT ON COLUMN chill_docgen_template.name IS \'(DC2Type:json_array)\''); } public function down(Schema $schema): void diff --git a/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php b/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php index a2a8167cc..35853fcd9 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php @@ -34,10 +34,10 @@ class DocumentCategory /** - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; - + public function __construct($bundleId, $idInsideBundle) { $this->bundleId = $bundleId; diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php index a0e614025..c6376b805 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -39,14 +39,14 @@ class StoredObject implements AsyncFileInterface, Document private $filename; /** - * @ORM\Column(type="json_array", name="key") + * @ORM\Column(type="json", name="key") */ private array $keyInfos = []; /** * * @var int[] - * @ORM\Column(type="json_array", name="iv") + * @ORM\Column(type="json", name="iv") */ private array $iv = []; @@ -69,7 +69,7 @@ class StoredObject implements AsyncFileInterface, Document private string $type = ''; /** - * @ORM\Column(type="json_array", name="datas") + * @ORM\Column(type="json", name="datas") * @Serializer\Groups({"read"}) */ private array $datas = []; diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php index 8dbc86473..97d971c6c 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php @@ -17,7 +17,6 @@ final class Version20180605102533 extends AbstractMigration $this->addSql('CREATE SCHEMA chill_doc'); $this->addSql('CREATE SEQUENCE chill_doc.person_document_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_doc.document_category (bundle_id VARCHAR(255) NOT NULL, id_inside_bundle INT NOT NULL, document_class VARCHAR(255) NOT NULL, name JSON NOT NULL, PRIMARY KEY(bundle_id, id_inside_bundle))'); - $this->addSql('COMMENT ON COLUMN chill_doc.document_category.name IS \'(DC2Type:json_array)\''); $this->addSql('CREATE TABLE chill_doc.person_document (id INT NOT NULL, category_bundle_id VARCHAR(255) DEFAULT NULL, category_id_inside_bundle INT DEFAULT NULL, scope_id INT DEFAULT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, title TEXT NOT NULL, description TEXT NOT NULL, content TEXT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_41DA53C369A0BE36EF62EFC ON chill_doc.person_document (category_bundle_id, category_id_inside_bundle)'); $this->addSql('CREATE INDEX IDX_41DA53C682B5931 ON chill_doc.person_document (scope_id)'); @@ -34,6 +33,6 @@ final class Version20180605102533 extends AbstractMigration $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->addSql('DROP SCHEMA chill_doc CASCADE'); - + } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php index b77debe7b..b0fae40fb 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php @@ -16,9 +16,6 @@ final class Version20180606133338 extends AbstractMigration $this->addSql('CREATE SEQUENCE chill_doc.stored_object_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_doc.stored_object (id INT NOT NULL, filename TEXT NOT NULL, key JSON NOT NULL, iv JSON NOT NULL, creation_date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, type TEXT NOT NULL, datas JSON NOT NULL, PRIMARY KEY(id))'); - $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.key IS \'(DC2Type:json_array)\''); - $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.iv IS \'(DC2Type:json_array)\''); - $this->addSql('COMMENT ON COLUMN chill_doc.stored_object.datas IS \'(DC2Type:json_array)\''); $this->addSql('ALTER TABLE chill_doc.person_document ADD object_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_doc.person_document DROP content'); $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C232D562B FOREIGN KEY (object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); diff --git a/src/Bundle/ChillEventBundle/Entity/EventType.php b/src/Bundle/ChillEventBundle/Entity/EventType.php index 8c67d8c81..c8b6b63c0 100644 --- a/src/Bundle/ChillEventBundle/Entity/EventType.php +++ b/src/Bundle/ChillEventBundle/Entity/EventType.php @@ -46,7 +46,7 @@ class EventType /** * @var array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -55,7 +55,7 @@ class EventType * @ORM\Column(type="boolean") */ private $active; - + /** * @var Collection * @ORM\OneToMany( diff --git a/src/Bundle/ChillEventBundle/Entity/Role.php b/src/Bundle/ChillEventBundle/Entity/Role.php index cf7d3a243..1f1bb93ad 100644 --- a/src/Bundle/ChillEventBundle/Entity/Role.php +++ b/src/Bundle/ChillEventBundle/Entity/Role.php @@ -44,7 +44,7 @@ class Role /** * @var array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; @@ -53,7 +53,7 @@ class Role * @ORM\Column(type="boolean") */ private $active; - + /** * @var EventType * @ORM\ManyToOne( diff --git a/src/Bundle/ChillEventBundle/Entity/Status.php b/src/Bundle/ChillEventBundle/Entity/Status.php index a88bff5c4..1f073fd7d 100644 --- a/src/Bundle/ChillEventBundle/Entity/Status.php +++ b/src/Bundle/ChillEventBundle/Entity/Status.php @@ -41,19 +41,19 @@ class Status * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + /** * @var array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; - + /** * @var boolean * @ORM\Column(type="boolean") */ private $active; - + /** * @var EventType * @ORM\ManyToOne( diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index b35ca5004..da53ba3af 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -107,6 +107,9 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $container->setParameter('chill_main.available_languages', $config['available_languages']); + $container->setParameter('chill_main.available_countries', + $config['available_countries']); + $container->setParameter('chill_main.routing.resources', $config['routing']['resources']); diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index b7cff5821..e75488ba6 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -51,6 +51,10 @@ class Configuration implements ConfigurationInterface ->defaultValue(array('fr')) ->prototype('scalar')->end() ->end() // end of array 'available_languages' + ->arrayNode('available_countries') + ->defaultValue(array('FR')) + ->prototype('scalar')->end() + ->end() // end of array 'available_countries' ->arrayNode('routing') ->children() ->arrayNode('resources') diff --git a/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php b/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php index 38c704a2d..3f95f7b6e 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Type/NativeDateIntervalType.php @@ -15,17 +15,17 @@ use Doctrine\DBAL\Types\ConversionException; class NativeDateIntervalType extends DateIntervalType { const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS'; - + public function getName(): string { - return \Doctrine\DBAL\Types\Type::DATEINTERVAL; + return \Doctrine\DBAL\Types\Types::DATEINTERVAL; } public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { return 'INTERVAL'; } - + /** * {@inheritdoc} */ @@ -41,36 +41,36 @@ class NativeDateIntervalType extends DateIntervalType throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); } - + public function convertToPHPValue($value, AbstractPlatform $platform) { if ($value === null || $value instanceof \DateInterval) { return $value; } - + try { $strings = explode(' ', $value); - + if (count($strings) === 0) { return null; } $intervalSpec = 'P'; \reset($strings); - + do { $intervalSpec .= $this->convertEntry($strings); } while (next($strings) !== FALSE); - + return new \DateInterval($intervalSpec); } catch (\Exception $exception) { throw $this->createConversionException($value, $exception); } } - + private function convertEntry(&$strings) { $current = \current($strings); - + if (is_numeric($current)) { $next = \next($strings); switch($next) { @@ -79,7 +79,7 @@ class NativeDateIntervalType extends DateIntervalType $unit = 'Y'; break; case 'mon': - case 'mons': + case 'mons': $unit = 'M'; break; case 'day': @@ -89,20 +89,20 @@ class NativeDateIntervalType extends DateIntervalType default: throw $this->createConversionException(implode('', $strings)); } - + return $current.$unit; - + } elseif (\preg_match('/([0-9]{2}\:[0-9]{2}:[0-9]{2})/', $current) === 1) { $tExploded = explode(':', $current); $intervalSpec = 'T'; $intervalSpec.= $tExploded[0].'H'; $intervalSpec.= $tExploded[1].'M'; $intervalSpec.= $tExploded[2].'S'; - + return $intervalSpec; } } - + protected function createConversionException($value, $exception = null) { return ConversionException::conversionFailedFormat($value, $this->getName(), 'xx year xx mons xx days 01:02:03', $exception); diff --git a/src/Bundle/ChillMainBundle/Entity/Country.php b/src/Bundle/ChillMainBundle/Entity/Country.php index 043a4e82e..df3f676b9 100644 --- a/src/Bundle/ChillMainBundle/Entity/Country.php +++ b/src/Bundle/ChillMainBundle/Entity/Country.php @@ -28,7 +28,7 @@ class Country /** * @var string * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") * @groups({"read"}) * */ diff --git a/src/Bundle/ChillMainBundle/Entity/Language.php b/src/Bundle/ChillMainBundle/Entity/Language.php index 22895b61b..8bbccd398 100644 --- a/src/Bundle/ChillMainBundle/Entity/Language.php +++ b/src/Bundle/ChillMainBundle/Entity/Language.php @@ -43,14 +43,14 @@ class Language /** * @var string array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; /** * Get id * - * @return string + * @return string */ public function getId() { @@ -59,7 +59,7 @@ class Language /** * Set id - * + * * @param string $id * @return Language */ @@ -78,17 +78,17 @@ class Language public function setName($name) { $this->name = $name; - + return $this; } /** * Get name * - * @return string array + * @return string array */ public function getName() { return $this->name; - } + } } diff --git a/src/Bundle/ChillMainBundle/Entity/Scope.php b/src/Bundle/ChillMainBundle/Entity/Scope.php index 2e75c5791..acd92099c 100644 --- a/src/Bundle/ChillMainBundle/Entity/Scope.php +++ b/src/Bundle/ChillMainBundle/Entity/Scope.php @@ -52,7 +52,7 @@ class Scope * * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") * @Groups({"read"}) */ private $name = []; diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 41d6db40c..2048667e1 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -116,7 +116,7 @@ class User implements AdvancedUserInterface { * Array where SAML attributes's data are stored * @var array * - * @ORM\Column(type="json_array", nullable=true) + * @ORM\Column(type="json", nullable=true) */ private $attributes; diff --git a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php index afcd061e6..3d3f2e9d8 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php @@ -54,7 +54,7 @@ class CommentType extends AbstractType $data = $event->getForm()->getData(); $comment = $event->getData() ?? ['comment' => '']; - if ($data->getComment() !== $comment['comment']) { + if (null !== $data && $data->getComment() !== $comment['comment']) { $data->setDate(new \DateTime()); $data->setUserId($this->user->getId()); $event->getForm()->setData($data); diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php index 617d1afce..c8288d69d 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php @@ -28,6 +28,7 @@ use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; use Doctrine\Persistence\ObjectManager; use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * Extends choice to allow adding select2 library on widget @@ -37,31 +38,25 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; */ class Select2CountryType extends AbstractType { - /** - * @var RequestStack - */ - private $requestStack; + private RequestStack $requestStack; - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + private ObjectManager $em; - /** - * @var ObjectManager - */ - private $em; + protected TranslatableStringHelper $translatableStringHelper; + + protected ParameterBagInterface $parameterBag; public function __construct( RequestStack $requestStack, ObjectManager $em, - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + ParameterBagInterface $parameterBag ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; + $this->parameterBag = $parameterBag; } public function getBlockPrefix() @@ -82,19 +77,29 @@ class Select2CountryType extends AbstractType public function configureOptions(OptionsResolver $resolver) { - $locale = $this->requestStack->getCurrentRequest()->getLocale(); $countries = $this->em->getRepository('Chill\MainBundle\Entity\Country')->findAll(); - $choices = array(); + $choices = []; + $preferredCountries = $this->parameterBag->get('chill_main.available_countries'); + $preferredChoices = []; foreach ($countries as $c) { $choices[$c->getId()] = $this->translatableStringHelper->localize($c->getName()); } + foreach ($preferredCountries as $pc) { + foreach ($countries as $c) { + if ($c->getCountryCode() == $pc) { + $preferredChoices[$c->getId()] = $this->translatableStringHelper->localize($c->getName()); + } + } + } + asort($choices, SORT_STRING | SORT_FLAG_CASE); $resolver->setDefaults(array( 'class' => 'Chill\MainBundle\Entity\Country', - 'choices' => array_combine(array_values($choices),array_keys($choices)) + 'choices' => array_combine(array_values($choices),array_keys($choices)), + 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)) )); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php index 2c8dea857..a50569967 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php @@ -28,37 +28,32 @@ use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer; use Doctrine\Persistence\ObjectManager; use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; /** * Extends choice to allow adding select2 library on widget for languages (multiple) */ class Select2LanguageType extends AbstractType { - /** - * @var RequestStack - */ - private $requestStack; + private RequestStack $requestStack; - /** - * @var ObjectManager - */ - private $em; + private ObjectManager $em; - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + protected TranslatableStringHelper $translatableStringHelper; + + protected ParameterBagInterface $parameterBag; public function __construct( RequestStack $requestStack, ObjectManager $em, - TranslatableStringHelper $translatableStringHelper + TranslatableStringHelper $translatableStringHelper, + ParameterBagInterface $parameterBag ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; + $this->parameterBag = $parameterBag; } public function getBlockPrefix() @@ -79,19 +74,24 @@ class Select2LanguageType extends AbstractType public function configureOptions(OptionsResolver $resolver) { - $locale = $this->requestStack->getCurrentRequest()->getLocale(); $languages = $this->em->getRepository('Chill\MainBundle\Entity\Language')->findAll(); - $choices = array(); + $preferredLanguages = $this->parameterBag->get('chill_main.available_languages'); + $choices = []; + $preferredChoices = []; foreach ($languages as $l) { $choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName()); } + foreach ($preferredLanguages as $l) { + $preferredChoices[$l] = $choices[$l]; + } asort($choices, SORT_STRING | SORT_FLAG_CASE); $resolver->setDefaults(array( 'class' => 'Chill\MainBundle\Entity\Language', - 'choices' => array_combine(array_values($choices),array_keys($choices)) + 'choices' => array_combine(array_values($choices), array_keys($choices)), + 'preferred_choices' => array_combine(array_values($preferredChoices), array_keys($preferredChoices)) )); } } diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/index.js b/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/index.js index 34f3b80b5..88890ab40 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/index.js @@ -1 +1,5 @@ -require("./show_hide.js"); \ No newline at end of file +//require("./show_hide.js"); + +import { ShowHide } from './show_hide.js' + +export { ShowHide } \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/show_hide.js b/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/show_hide.js index dd4dfd6db..ec6b796ec 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/show_hide.js +++ b/src/Bundle/ChillMainBundle/Resources/public/lib/show_hide/show_hide.js @@ -134,4 +134,4 @@ var ShowHide = function(options) { }; }; -export {ShowHide}; +export { ShowHide }; diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js index ad4a648f5..0f39c5e75 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js @@ -5,82 +5,89 @@ import App from './App.vue'; const i18n = _createI18n(addressMessages); -let inputs = document.querySelectorAll('input[type="hidden"][data-input-address]'); +const addAddressInput = (inputs) => { -const isNumeric = function(v) { return !isNaN(v); }; + inputs.forEach(el => { + let + addressId = el.value, + uniqid = el.dataset.inputAddress, + container = document.querySelector('div[data-input-address-container="' + uniqid + '"]'), + isEdit = addressId !== '', + addressIdInt = addressId !== '' ? parseInt(addressId) : null + ; -inputs.forEach(el => { - let - addressId = el.value, - uniqid = el.dataset.inputAddress, - container = document.querySelector('div[data-input-address-container="' + uniqid + '"]'), - isEdit = addressId !== '', - addressIdInt = addressId !== '' ? parseInt(addressId) : null - ; + if (container === null) { + throw Error("no container"); + } + console.log('useValidFrom', el.dataset.useValidFrom === '1'); - if (container === null) { - throw Error("no container"); - } - console.log('useValidFrom', el.dataset.useValidFrom === '1'); - - const app = createApp({ - template: ``, - data() { - return { - addAddress: { - context: { - // for legacy ? can be remove ? - target: { - name: 'input-address', - id: addressIdInt, - }, - edit: isEdit, - addressId: addressIdInt, - }, - options: { - /// Options override default. - /// null value take default component value defined in AddAddress data() - button: { - text: { - create: el.dataset.buttonTextCreate || null, - edit: el.dataset.buttonTextUpdate || null, + const app = createApp({ + template: ``, + data() { + return { + addAddress: { + context: { + // for legacy ? can be remove ? + target: { + name: 'input-address', + id: addressIdInt, }, - size: null, - displayText: true + edit: isEdit, + addressId: addressIdInt, }, + options: { + /// Options override default. + /// null value take default component value defined in AddAddress data() + button: { + text: { + create: el.dataset.buttonTextCreate || null, + edit: el.dataset.buttonTextUpdate || null, + }, + size: null, + displayText: true + }, - /// Modal title text if create or edit address (trans chain, see i18n) - title: { - create: null, - edit: null, - }, + /// Modal title text if create or edit address (trans chain, see i18n) + title: { + create: null, + edit: null, + }, - /// Display panes in Modal for step123 - openPanesInModal: true, + /// Display panes in Modal for step123 + openPanesInModal: true, - /// Display actions buttons of panes in a sticky-form-button navbar - stickyActions: false, - showMessageWhenNoAddress: true, + /// Display actions buttons of panes in a sticky-form-button navbar + stickyActions: false, + showMessageWhenNoAddress: true, - /// Use Date fields - useDate: { - validFrom: el.dataset.useValidFrom === '1' || false, //boolean, default: false - validTo: el.dataset.useValidTo === '1' || false, //boolean, default: false - }, + /// Use Date fields + useDate: { + validFrom: el.dataset.useValidFrom === '1' || false, //boolean, default: false + validTo: el.dataset.useValidTo === '1' || false, //boolean, default: false + }, - /// Don't display show renderbox Address: showPane display only a button - onlyButton: false, + /// Don't display show renderbox Address: showPane display only a button + onlyButton: false, + } } } + }, + methods: { + associateToInput(payload) { + el.value = payload.addressId; + } } - }, - methods: { - associateToInput(payload) { - el.value = payload.addressId; - } - } - }) - .use(i18n) - .component('app', App) - .mount(container); -}); + }) + .use(i18n) + .component('app', App) + .mount(container); + }); +}; + +document.addEventListener('DOMContentLoaded', (_e) => + addAddressInput(document.querySelectorAll('input[type="hidden"][data-input-address]')) +); + +window.addEventListener('collection-add-entry', (e) => + addAddressInput(e.detail.entry.querySelectorAll('input[type="hidden"][data-input-address]')) +); \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/config/config.yml b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/config/config.yml index b16af4de1..530c29ee6 100644 --- a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/config/config.yml +++ b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/config/config.yml @@ -39,3 +39,4 @@ assetic: chill_main: available_languages: [fr, en] + available_countries: [FR] diff --git a/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig index b1bdb8438..104f46b27 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig @@ -83,6 +83,10 @@ {% endmacro %} +{# + this enclose the rendering inside a "li", which ease the placement operation when the address + must be shown in such list +#} {%- if render == 'list' -%}
  • {% if options['with_picto'] %} diff --git a/src/Bundle/ChillMainBundle/Security/ParentRoleHelper.php b/src/Bundle/ChillMainBundle/Security/ParentRoleHelper.php index 07366dafa..0d0fd0b94 100644 --- a/src/Bundle/ChillMainBundle/Security/ParentRoleHelper.php +++ b/src/Bundle/ChillMainBundle/Security/ParentRoleHelper.php @@ -33,12 +33,14 @@ class ParentRoleHelper * Return all the role which give access to the given role. Only the role * which are registered into Chill are taken into account. * + * The array contains always the current $role (which give access to himself) + * * @param string $role * @return string[] the role which give access to the given $role */ public function getParentRoles(string $role): array { - $parentRoles = []; + $parentRoles = [$role]; // transform the roles from role hierarchy from string to Role $roles = \array_keys($this->hierarchy); diff --git a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php index 0a28d39ca..8f349da4b 100644 --- a/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/Listing/FilterOrderHelper.php @@ -14,7 +14,7 @@ class FilterOrderHelper private ?array $searchBoxFields = null; private array $checkboxes = []; private ?array $submitted = null; - private ?string $formName = 'filter'; + private ?string $formName = 'f'; private string $formType = FilterOrderType::class; private array $formOptions = []; diff --git a/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php index 0d718ec09..5f98879b4 100644 --- a/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Authorization/ParentRoleHelperTest.php @@ -23,9 +23,10 @@ class ParentRoleHelperTest extends KernelTestCase $parentRoles = $this->parentRoleHelper->getParentRoles(PersonVoter::SEE); - $this->assertCount(2, $parentRoles); + $this->assertCount(3, $parentRoles); $this->assertContains(PersonVoter::CREATE, $parentRoles); $this->assertContains(PersonVoter::UPDATE, $parentRoles); + $this->assertContains(PersonVoter::SEE, $parentRoles); } public function testIsRoleReached() diff --git a/src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php b/src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php index de2ae9975..e2e266a70 100644 --- a/src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php +++ b/src/Bundle/ChillMainBundle/Timeline/TimelineBuilder.php @@ -20,7 +20,7 @@ namespace Chill\MainBundle\Timeline; use Doctrine\ORM\Query\ResultSetMapping; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Doctrine\ORM\Query; @@ -31,38 +31,38 @@ use Doctrine\ORM\NativeQuery; */ class TimelineBuilder implements ContainerAwareInterface { - + use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - + /** * * @var \Doctrine\ORM\EntityManagerInterface */ private $em; - + /** * Record provider - * + * * This array has the structure `[ 'service id' => $service ]` * * @var TimelineProviderInterface[] */ private $providers = []; - + /** * Record provider and their context - * + * * This array has the structure `[ 'context' => [ 'service id' ] ]` * * @var array */ private $providersByContext = []; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - + /** * return an HTML string with timeline * @@ -79,18 +79,18 @@ class TimelineBuilder implements ContainerAwareInterface public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20) { list($union, $parameters) = $this->buildUnionQuery($context, $args); - + //add ORDER BY clause and LIMIT $query = $union . sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d', $number, $firstItem); - + // run query and handle results $fetched = $this->runUnionQuery($query, $parameters); $entitiesByKey = $this->getEntities($fetched, $context); - + return $this->render($fetched, $entitiesByKey, $context, $args); } - + /** * Return the number of items for the given context and args * @@ -101,7 +101,7 @@ class TimelineBuilder implements ContainerAwareInterface public function countItems($context, array $args) { $rsm = (new ResultSetMapping()) - ->addScalarResult('total', 'total', Type::INTEGER); + ->addScalarResult('total', 'total', Types::INTEGER); list($select, $parameters) = $this->buildUnionQuery($context, $args); @@ -110,10 +110,10 @@ class TimelineBuilder implements ContainerAwareInterface $nq = $this->em->createNativeQuery($countQuery, $rsm); $nq->setParameters($parameters); - + return $nq->getSingleScalarResult(); } - + /** * add a provider id * @@ -127,7 +127,7 @@ class TimelineBuilder implements ContainerAwareInterface $this->providersByContext[$context][] = $id; $this->providers[$id] = $provider; } - + /** * Get providers by context * @@ -141,16 +141,16 @@ class TimelineBuilder implements ContainerAwareInterface throw new \LogicException(sprintf('No builders have been defined for "%s"' . ' context', $context)); } - + $providers = []; - + foreach($this->providersByContext[$context] as $providerId) { $providers[] = $this->providers[$providerId]; } - + return $providers; } - + /** * build the UNION query with all providers * @@ -172,7 +172,7 @@ class TimelineBuilder implements ContainerAwareInterface $union .= $append; $parameters = array_merge($parameters, $selectParameters); } - + return [$union, $parameters]; } @@ -195,7 +195,7 @@ class TimelineBuilder implements ContainerAwareInterface return $s; } */ - + /** * return the SQL SELECT query as a string, * @@ -222,9 +222,9 @@ class TimelineBuilder implements ContainerAwareInterface ); return [$sql, $data['WHERE'][1]]; - + } - + /** * run the UNION query and return result as an array * @@ -236,12 +236,12 @@ class TimelineBuilder implements ContainerAwareInterface ->addScalarResult('id', 'id') ->addScalarResult('type', 'type') ->addScalarResult('date', 'date'); - + return $this->em->createNativeQuery($query, $resultSetMapping) ->setParameters($parameters) ->getArrayResult(); } - + /** * * @param array $queriedIds @@ -252,11 +252,11 @@ class TimelineBuilder implements ContainerAwareInterface { //gather entities by type to pass all id with same type to the TimelineProvider. $idsByType = array(); - + foreach($queriedIds as $result) { $idsByType[$result['type']][] = $result['id']; } - + //fetch entities from providers $entitiesByType = array(); foreach ($idsByType as $type => $ids) { @@ -268,10 +268,10 @@ class TimelineBuilder implements ContainerAwareInterface } } } - + return $entitiesByType; } - + /** * render the timeline as HTML * @@ -294,17 +294,17 @@ class TimelineBuilder implements ContainerAwareInterface $timelineEntry['date'] = new \DateTime($result['date']); $timelineEntry['template'] = $data['template']; $timelineEntry['template_data'] = $data['template_data']; - + $timelineEntries[] = $timelineEntry; } - + return $this->container->get('templating') ->render('@ChillMain/Timeline/chain_timelines.html.twig', array( 'results' => $timelineEntries )); - + } - + /** * get the template data from the provider for the given entity, by type. * diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index b3eb0ca98..27d018229 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -25,6 +25,7 @@ services: - "@request_stack" - "@doctrine.orm.entity_manager" - "@chill.main.helper.translatable_string" + - '@Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface' tags: - { name: form.type, alias: select2_chill_country } @@ -34,6 +35,7 @@ services: - "@request_stack" - "@doctrine.orm.entity_manager" - "@chill.main.helper.translatable_string" + - '@Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface' tags: - { name: form.type, alias: select2_chill_language } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php b/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php index 5f1fb6869..159de82f6 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php @@ -20,7 +20,6 @@ final class Version20210304085819 extends AbstractMigration public function up(Schema $schema) : void { $this->addSql('ALTER TABLE users ADD attributes JSONB DEFAULT NULL'); - $this->addSql('COMMENT ON COLUMN users.attributes IS \'(DC2Type:json_array)\''); } public function down(Schema $schema) : void diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php index 1b9824184..6dbf8b6a5 100644 --- a/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php +++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdController.php @@ -14,6 +14,8 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Chill\PersonBundle\Entity\Household\Household; use Chill\PersonBundle\Entity\Household\Position; use Chill\PersonBundle\Repository\Household\PositionRepository; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; +use Symfony\Component\Security\Core\Security; /** * @Route("/{_locale}/person/household") @@ -24,11 +26,14 @@ class HouseholdController extends AbstractController private PositionRepository $positionRepository; - public function __construct(TranslatorInterface $translator, PositionRepository $positionRepository) + private Security $security; + + public function __construct(TranslatorInterface $translator, PositionRepository $positionRepository, Security $security) { $this->translator = $translator; $this->positionRepository = $positionRepository; + $this->security = $security; } /** @@ -77,17 +82,46 @@ class HouseholdController extends AbstractController */ public function accompanyingPeriod(Request $request, Household $household) { - // TODO ACL - $members = $household->getMembers(); - foreach($members as $m) { - $accompanyingPeriods = $m->getPerson()->getAccompanyingPeriods(); + $currentMembers = $household->getCurrentPersons(); + $accompanyingPeriods = []; + + foreach ($currentMembers as $p) { + $accompanyingPeriodsMember = $p->getCurrentAccompanyingPeriods(); + + foreach ($accompanyingPeriodsMember as $accompanyingPeriod) { + if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) { + continue; + } else { + $accompanyingPeriods[$accompanyingPeriod->getId()] = $accompanyingPeriod; + } + } + } + + $oldMembers = $household->getNonCurrentMembers(); + $accompanyingPeriodsOld = []; + + foreach ($oldMembers as $m) { + $accompanyingPeriodsOldMember = $m->getPerson()->getAccompanyingPeriods(); + + foreach ($accompanyingPeriodsOldMember as $accompanyingPeriod) { + if (!$this->security->isGranted(AccompanyingPeriodVoter::SEE, $accompanyingPeriod)) { + continue; + } else { + $id = $accompanyingPeriod->getId(); + + if (!array_key_exists($id, $accompanyingPeriodsOld) && !array_key_exists($id, $accompanyingPeriods)) { + $accompanyingPeriodsOld[$id] = $accompanyingPeriod; + } + } + } } return $this->render('@ChillPerson/Household/accompanying_period.html.twig', [ 'household' => $household, - 'accompanying_periods' => $accompanyingPeriods + 'accompanying_periods' => $accompanyingPeriods, + 'accompanying_periods_old' => $accompanyingPeriodsOld ] ); } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php index bf2d18922..2c53af0fe 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -77,11 +77,13 @@ class Configuration implements ConfigurationInterface ->append($this->addFieldNode('nationality')) ->append($this->addFieldNode('country_of_birth')) ->append($this->addFieldNode('marital_status')) + ->append($this->addFieldNode('civility')) ->append($this->addFieldNode('spoken_languages')) ->append($this->addFieldNode('address')) ->append($this->addFieldNode('accompanying_period')) ->append($this->addFieldNode('memo')) ->append($this->addFieldNode('number_of_children')) + ->append($this->addFieldNode('acceptEmail')) ->arrayNode('alt_names') ->defaultValue([]) ->arrayPrototype() diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php index 46ae02ce0..7ff90b652 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php @@ -41,7 +41,7 @@ class Household * targetEntity="Chill\MainBundle\Entity\Address", * cascade={"persist", "remove", "merge", "detach"}) * @ORM\JoinTable(name="chill_person_household_to_addresses") - * @ORM\OrderBy({"validFrom" = "DESC"}) + * @ORM\OrderBy({"validFrom" = "DESC", "id" = "DESC"}) * @Serializer\Groups({"write"}) */ private Collection $addresses; @@ -245,6 +245,16 @@ class Household $members->getIterator() ->uasort( function (HouseholdMember $a, HouseholdMember $b) { + if ($a->getPosition() === NULL) { + if ($b->getPosition() === NULL) { + return 0; + } else { + return -1; + } + } elseif ($b->getPosition() === NULL) { + return 1; + } + if ($a->getPosition()->getOrdering() < $b->getPosition()->getOrdering()) { return -1; } @@ -334,6 +344,26 @@ class Household return $this->getNonCurrentMembers($now)->matching($criteria); } + public function getCurrentMembersWithoutPosition(\DateTimeInterface $now = null) + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where($expr->isNull('position')); + + return $this->getCurrentMembers($now)->matching($criteria); + } + + public function getNonCurrentMembersWithoutPosition(\DateTimeInterface $now = null) + { + $criteria = new Criteria(); + $expr = Criteria::expr(); + + $criteria->where($expr->isNull('position')); + + return $this->getNonCurrentMembers($now)->matching($criteria); + } + public function addMember(HouseholdMember $member): self { if (!$this->members->contains($member)) { diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php index 985084623..d157aa58a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMember.php @@ -29,7 +29,7 @@ class HouseholdMember /** * @ORM\ManyToOne(targetEntity=Position::class) * @Serializer\Groups({"read"}) - * @Assert\NotNull(groups={"household_memberships"}) + * @Assert\NotNull(groups={"household_memberships_created"}) */ private ?Position $position = null; @@ -159,6 +159,12 @@ class HouseholdMember return $this->shareHousehold; } + public function setShareHousehold(bool $shareHousehold): self + { + $this->shareHousehold = $shareHousehold; + + return $this; + } public function getPerson(): ?Person { diff --git a/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php b/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php index 43ae1b09f..67185c36a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php +++ b/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php @@ -41,14 +41,14 @@ class MaritalStatus /** * @var string array - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $name; /** * Get id * - * @return string + * @return string */ public function getId() { @@ -57,7 +57,7 @@ class MaritalStatus /** * Set id - * + * * @param string $id * @return MaritalStatus */ @@ -76,17 +76,17 @@ class MaritalStatus public function setName($name) { $this->name = $name; - + return $this; } /** * Get name * - * @return string array + * @return string array */ public function getName() { return $this->name; - } + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 9aaad8c04..5e521b60a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -34,6 +34,7 @@ use Chill\PersonBundle\Entity\MaritalStatus; use Chill\PersonBundle\Entity\Household\HouseholdMember; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Civility; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\PersonBundle\Entity\Person\PersonCurrentAddress; use DateTime; @@ -212,6 +213,15 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI */ private $maritalStatus; + /** + * The marital status of the person + * @var Civility + * + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Civility") + * @ORM\JoinColumn(nullable=true) + */ + private $civility; + /** * The date of the last marital status change of the person * @var \DateTime @@ -406,7 +416,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI * Array where customfield's data are stored * @var array * - * @ORM\Column(type="json_array") + * @ORM\Column(type="json") */ private $cFData; @@ -613,6 +623,26 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $accompanyingPeriods; } + /** + * Get current accompanyingPeriods array + */ + public function getCurrentAccompanyingPeriods(): array + { + $currentAccompanyingPeriods = []; + $currentDate = new DateTime(); + + foreach ($this->accompanyingPeriodParticipations as $participation) + { + $endDate = $participation->getEndDate(); + + if ($endDate === null || $endDate > $currentDate){ + $currentAccompanyingPeriods[] = $participation->getAccompanyingPeriod(); + } + } + + return $currentAccompanyingPeriods; + } + /** * Get AccompanyingPeriodParticipations Collection * @@ -962,6 +992,28 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI return $this->maritalStatus; } + /** + * Set civility + * + * @param Civility $civility + * @return Person + */ + public function setCivility(Civility $civility = null) + { + $this->civility = $civility; + return $this; + } + + /** + * Get civility + * + * @return Civility + */ + public function getCivility() + { + return $this->civility; + } + /** * Set contactInfo * @@ -1283,11 +1335,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI /** * get the address associated with the person at the given date * + * If the `$at` parameter is now, use the method `getCurrentPersonAddress`, which is optimized + * on database side. + * * @param DateTime|null $at * @return Address|null * @throws \Exception */ - public function getCurrentPersonAddress(?\DateTime $at = null): ?Address + public function getAddressAt(?\DateTime $at = null): ?Address { $at ??= new DateTime('now'); @@ -1305,6 +1360,20 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI current($addresses); } + /** + * Get the current person address + * + * @return Address|null + */ + public function getCurrentPersonAddress(): ?Address + { + if (null === $this->currentPersonAddress) { + return null; + } + + return $this->currentPersonAddress->getAddress(); + } + /** * Validation callback that checks if the accompanying periods are valid * diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php index 7179de4d3..fbf59168c 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php @@ -21,11 +21,11 @@ use Chill\MainBundle\Export\FilterInterface; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; /** - * + * * */ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface @@ -38,14 +38,14 @@ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportEl public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX( $qb->expr()->lte('accompanying_period.closingDate', ':date_to'), $qb->expr()->gte('accompanying_period.closingDate', ':date_from')); $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Type::DATE); - $qb->setParameter('date_to', $data['date_to'], Type::DATE); + $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); + $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); } public function applyOn(): string @@ -59,7 +59,7 @@ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportEl 'label' => "Having an accompanying period closed after this date", 'data' => new \DateTime("-1 month"), )); - + $builder->add('date_to', ChillDateType::class, array( 'label' => "Having an accompanying period closed before this date", 'data' => new \DateTime(), diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php index 40f7dd501..be732a028 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php @@ -21,11 +21,11 @@ use Chill\MainBundle\Export\FilterInterface; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; /** - * + * * */ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface @@ -38,9 +38,9 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX(); - + $clause->add( $qb->expr()->lte('accompanying_period.openingDate', ':date_to') ); @@ -52,8 +52,8 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i ); $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Type::DATE); - $qb->setParameter('date_to', $data['date_to'], Type::DATE); + $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); + $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); } public function applyOn(): string @@ -67,7 +67,7 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i 'label' => "Having an accompanying period opened after this date", 'data' => new \DateTime("-1 month"), )); - + $builder->add('date_to', ChillDateType::class, array( 'label' => "Having an accompanying period ending before this date, or " . "still opened at this date", diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php index 26a8818df..6c81e6e65 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php @@ -21,11 +21,11 @@ use Chill\MainBundle\Export\FilterInterface; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Types\Types; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; /** - * + * * */ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface @@ -38,14 +38,14 @@ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportEl public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX( $qb->expr()->lte('accompanying_period.openingDate', ':date_to'), $qb->expr()->gte('accompanying_period.openingDate', ':date_from')); $qb->andWhere($clause); - $qb->setParameter('date_from', $data['date_from'], Type::DATE); - $qb->setParameter('date_to', $data['date_to'], Type::DATE); + $qb->setParameter('date_from', $data['date_from'], Types::DATE_MUTABLE); + $qb->setParameter('date_to', $data['date_to'], Types::DATE_MUTABLE); } public function applyOn(): string @@ -59,7 +59,7 @@ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportEl 'label' => "Having an accompanying period opened after this date", 'data' => new \DateTime("-1 month"), )); - + $builder->add('date_to', ChillDateType::class, array( 'label' => "Having an accompanying period opened before this date", 'data' => new \DateTime(), diff --git a/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php index 4d8d5a165..05a65c7d7 100644 --- a/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php +++ b/src/Bundle/ChillPersonBundle/Form/HouseholdMemberType.php @@ -16,13 +16,7 @@ class HouseholdMemberType extends AbstractType ->add('startDate', ChillDateType::class, [ 'label' => 'household.Start date', 'input' => 'datetime_immutable', - ]) - ->add('endDate', ChillDateType::class, [ - 'label' => 'household.End date', - 'input' => 'datetime_immutable', - 'required' => false - ]) - ; + ]); if ($options['data']->getPosition()->isAllowHolder()) { $builder ->add('holder', ChoiceType::class, [ diff --git a/src/Bundle/ChillPersonBundle/Form/PersonType.php b/src/Bundle/ChillPersonBundle/Form/PersonType.php index 8bc982713..521d9a9d9 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonType.php @@ -22,6 +22,7 @@ namespace Chill\PersonBundle\Form; use Chill\CustomFieldsBundle\Form\Type\CustomFieldType; +use Chill\MainBundle\Entity\Civility; use Chill\MainBundle\Form\Type\ChillCollectionType; use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\Select2CountryType; @@ -35,6 +36,11 @@ use Chill\PersonBundle\Form\Type\Select2MaritalStatusType; use Symfony\Component\Form\AbstractType; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\CommentType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\QueryBuilder; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TelType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -62,16 +68,20 @@ class PersonType extends AbstractType */ protected $configAltNamesHelper; + protected TranslatableStringHelper $translatableStringHelper; + /** * * @param string[] $personFieldsConfiguration configuration of visibility of some fields */ public function __construct( array $personFieldsConfiguration, - ConfigPersonAltNamesHelper $configAltNamesHelper + ConfigPersonAltNamesHelper $configAltNamesHelper, + TranslatableStringHelper $translatableStringHelper ) { $this->config = $personFieldsConfiguration; $this->configAltNamesHelper = $configAltNamesHelper; + $this->translatableStringHelper = $translatableStringHelper; } /** @@ -114,7 +124,19 @@ class PersonType extends AbstractType } if ($this->config['place_of_birth'] === 'visible') { - $builder->add('placeOfBirth', TextType::class, array('required' => false)); + $builder->add('placeOfBirth', TextType::class, array( + 'required' => false, + 'attr' => ['style' => 'text-transform: uppercase;'], + )); + + $builder->get('placeOfBirth')->addModelTransformer(new CallbackTransformer( + function ($string) { + return strtoupper($string); + }, + function ($string) { + return strtoupper($string); + } + )); } if ($this->config['contact_info'] === 'visible') { @@ -150,7 +172,11 @@ class PersonType extends AbstractType if ($this->config['email'] === 'visible') { $builder - ->add('email', EmailType::class, array('required' => false)) + ->add('email', EmailType::class, array('required' => false)); + } + + if ($this->config['acceptEmail'] === 'visible') { + $builder ->add('acceptEmail', CheckboxType::class, array('required' => false)); } @@ -173,6 +199,23 @@ class PersonType extends AbstractType )); } + if ($this->config['civility'] === 'visible'){ + $builder + ->add('civility', EntityType::class, [ + 'label' => 'Civility', + 'class' => Civility::class, + 'choice_label' => function (Civility $civility): string { + return $this->translatableStringHelper->localize($civility->getName()); + }, + 'query_builder' => function (EntityRepository $er): QueryBuilder { + return $er->createQueryBuilder('c') + ->where('c.active = true'); + }, + 'placeholder' => 'choose civility', + 'required' => false + ]); + } + if ($this->config['marital_status'] === 'visible'){ $builder ->add('maritalStatus', Select2MaritalStatusType::class, array( @@ -192,6 +235,7 @@ class PersonType extends AbstractType array('attr' => array('class' => 'cf-fields'), 'group' => $options['cFGroup'])) ; } + } /** diff --git a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php index 2fd322bb4..f718bb8a9 100644 --- a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php +++ b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php @@ -19,15 +19,17 @@ class MembersEditor private array $persistables = []; private array $membershipsAffected = []; + private array $oldMembershipsHashes = []; - public const VALIDATION_GROUP = 'household_memberships'; + public const VALIDATION_GROUP_CREATED = 'household_memberships_created'; + public const VALIDATION_GROUP_AFFECTED = 'household_memberships'; public function __construct(ValidatorInterface $validator, ?Household $household) { $this->validator = $validator; $this->household = $household; } - + public function addMovement(\DateTimeImmutable $date, Person $person, Position $position, ?bool $holder = false, ?string $comment = null): self { if (NULL === $this->household) { @@ -56,6 +58,7 @@ class MembersEditor if ($participation->getEndDate() === NULL || $participation->getEndDate() > $date) { $participation->setEndDate($date); $this->membershipsAffected[] = $participation; + $this->oldMembershipsHashes[] = \spl_object_hash($participation); } } } @@ -97,13 +100,18 @@ class MembersEditor { if ($this->hasHousehold()) { $list = $this->validator - ->validate($this->getHousehold(), null, [ self::VALIDATION_GROUP ]); + ->validate($this->getHousehold(), null, [ self::VALIDATION_GROUP_AFFECTED ]); } else { $list = new ConstraintViolationList(); } foreach ($this->membershipsAffected as $m) { - $list->addAll($this->validator->validate($m, null, [ self::VALIDATION_GROUP ])); + if (\in_array(\spl_object_hash($m), $this->oldMembershipsHashes)) { + $list->addAll($this->validator->validate($m, null, [ self::VALIDATION_GROUP_AFFECTED ])); + } else { + $list->addAll($this->validator->validate($m, null, [ self::VALIDATION_GROUP_CREATED, + self::VALIDATION_GROUP_AFFECTED ])); + } } return $list; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/page/person/index.js b/src/Bundle/ChillPersonBundle/Resources/public/page/person/index.js index d641e3b36..28ae3380a 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/page/person/index.js +++ b/src/Bundle/ChillPersonBundle/Resources/public/page/person/index.js @@ -7,7 +7,6 @@ const personAcceptEmail = document.getElementById("personAcceptEmail"); const personPhoneNumber = document.getElementById("personPhoneNumber"); const personAcceptSMS = document.getElementById("personAcceptSMS"); - new ShowHide({ froms: [maritalStatus], container: [maritalStatusDate], @@ -24,21 +23,24 @@ new ShowHide({ event_name: 'change' }); -new ShowHide({ - froms: [personEmail], - container: [personAcceptEmail], - test: function(froms) { - for (let f of froms.values()) { - for (let input of f.querySelectorAll('input').values()) { - if (input.value) { - return true +if (personAcceptEmail) { + new ShowHide({ + froms: [personEmail], + container: [personAcceptEmail], + test: function(froms) { + for (let f of froms.values()) { + for (let input of f.querySelectorAll('input').values()) { + if (input.value) { + return true + } } } - } - return false; - }, - event_name: 'input' -}); + return false; + }, + event_name: 'input' + }); +} + new ShowHide({ froms: [personPhoneNumber], diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue index b6333b426..fe7838c4d 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkCreate/App.vue @@ -9,7 +9,7 @@

    {{ $t('pick_social_issue_linked_with_action') }}

    - {{ si.title.fr }} + {{ si.text }}
    @@ -222,3 +222,16 @@ export default { } + + \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/config/config_test_with_hidden_fields.yml b/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/config/config_test_with_hidden_fields.yml index e11599661..0b12be8d0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/config/config_test_with_hidden_fields.yml +++ b/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/config/config_test_with_hidden_fields.yml @@ -15,4 +15,5 @@ chill_person: phonenumber: hidden country_of_birth: hidden marital_status: hidden - spoken_languages: hidden \ No newline at end of file + spoken_languages: hidden + civility: hidden \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/create.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/create.html.twig index b1d4682d8..b09f91cfd 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/create.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourseWork/create.html.twig @@ -18,6 +18,7 @@ window.accompanyingCourse = {{ json|json_encode|raw }}; + {{ parent() }} {{ encore_entry_script_tags('vue_accourse_work_create') }} {% endblock %} diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig index a53a7c0d0..c5797a4b2 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingPeriod/_list.html.twig @@ -77,7 +77,7 @@