diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php index e3ce8b287..b897cde8c 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialActionFilter.php @@ -14,10 +14,9 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use Chill\PersonBundle\Form\Type\PickSocialActionType; use Chill\PersonBundle\Templating\Entity\SocialActionRender; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -37,22 +36,17 @@ class BySocialActionFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $where = $qb->getDQLPart('where'); - if (!in_array('actsocialaction', $qb->getAllAliases(), true)) { $qb->join('activity.socialActions', 'actsocialaction'); } $clause = $qb->expr()->in('actsocialaction.id', ':socialactions'); - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('socialactions', $data['accepted_socialactions']); + $qb->andWhere($clause) + ->setParameter( + 'socialactions', + SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions']) + ); } public function applyOn(): string @@ -62,13 +56,8 @@ class BySocialActionFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_socialactions', EntityType::class, [ - 'class' => SocialAction::class, - 'choice_label' => function (SocialAction $sa) { - return $this->actionRender->renderString($sa, []); - }, + $builder->add('accepted_socialactions', PickSocialActionType::class, [ 'multiple' => true, - 'expanded' => true, ]); } @@ -76,8 +65,10 @@ class BySocialActionFilter implements FilterInterface { $actions = []; - foreach ($data['accepted_socialactions'] as $sa) { - $actions[] = $this->actionRender->renderString($sa, []); + foreach ($data['accepted_socialactions'] as $action) { + $actions[] = $this->actionRender->renderString($action, [ + 'show_and_children' => true, + ]); } return ['Filtered activity by linked socialaction: only %actions%', [ diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php index f5d552011..f827c8c56 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/BySocialIssueFilter.php @@ -14,10 +14,9 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use Chill\PersonBundle\Form\Type\PickSocialIssueType; use Chill\PersonBundle\Templating\Entity\SocialIssueRender; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -37,22 +36,17 @@ class BySocialIssueFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - $where = $qb->getDQLPart('where'); - if (!in_array('actsocialissue', $qb->getAllAliases(), true)) { $qb->join('activity.socialIssues', 'actsocialissue'); } $clause = $qb->expr()->in('actsocialissue.id', ':socialissues'); - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('socialissues', $data['accepted_socialissues']); + $qb->andWhere($clause) + ->setParameter( + 'socialissues', + SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues']) + ); } public function applyOn(): string @@ -62,13 +56,8 @@ class BySocialIssueFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_socialissues', EntityType::class, [ - 'class' => SocialIssue::class, - 'choice_label' => function (SocialIssue $si) { - return $this->issueRender->renderString($si, []); - }, + $builder->add('accepted_socialissues', PickSocialIssueType::class, [ 'multiple' => true, - 'expanded' => true, ]); } @@ -76,8 +65,10 @@ class BySocialIssueFilter implements FilterInterface { $issues = []; - foreach ($data['accepted_socialissues'] as $si) { - $issues[] = $this->issueRender->renderString($si, []); + foreach ($data['accepted_socialissues'] as $issue) { + $issues[] = $this->issueRender->renderString($issue, [ + 'show_and_children' => true, + ]); } return ['Filtered activity by linked socialissue: only %issues%', [ diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php index 023882cf9..2c9244022 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/LocationTypeFilter.php @@ -13,7 +13,7 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Export\Declarations; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\Select2LocationTypeType; +use Chill\MainBundle\Form\Type\PickLocationTypeType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; @@ -60,7 +60,7 @@ class LocationTypeFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_locationtype', Select2LocationTypeType::class, [ + $builder->add('accepted_locationtype', PickLocationTypeType::class, [ 'multiple' => true, //'label' => false, ]); diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index 03d8d2692..9d3941411 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -15,7 +15,7 @@ use Chill\MainBundle\CRUD\Controller\CRUDController; use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ComposedGroupCenterType; -use Chill\MainBundle\Form\Type\Select2UserLocationType; +use Chill\MainBundle\Form\UserCurrentLocationType; use Chill\MainBundle\Form\UserPasswordType; use Chill\MainBundle\Form\UserType; use Chill\MainBundle\Pagination\PaginatorInterface; @@ -234,7 +234,7 @@ class UserController extends CRUDController public function editCurrentLocationAction(Request $request) { $user = $this->getUser(); - $form = $this->createForm(Select2UserLocationType::class, $user) + $form = $this->createForm(UserCurrentLocationType::class, $user) ->add('submit', SubmitType::class, ['label' => 'Save']) ->handleRequest($request); diff --git a/src/Bundle/ChillMainBundle/Form/Type/PickLocationTypeType.php b/src/Bundle/ChillMainBundle/Form/Type/PickLocationTypeType.php new file mode 100644 index 000000000..6774e0941 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/Type/PickLocationTypeType.php @@ -0,0 +1,50 @@ +translatableStringHelper = $translatableStringHelper; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults([ + 'class' => LocationType::class, + 'choice_label' => function (LocationType $type) { + return $this->translatableStringHelper->localize($type->getTitle()); + }, + 'placeholder' => 'Pick a location type', + 'required' => false, + 'attr' => ['class' => 'select2'], + 'label' => 'Location type', + 'multiple' => false, + ]) + ->setAllowedTypes('multiple', ['bool']); + } + + public function getParent(): string + { + return EntityType::class; + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2UserLocationType.php b/src/Bundle/ChillMainBundle/Form/Type/PickUserLocationType.php similarity index 72% rename from src/Bundle/ChillMainBundle/Form/Type/Select2UserLocationType.php rename to src/Bundle/ChillMainBundle/Form/Type/PickUserLocationType.php index 8fb100441..792daa39e 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2UserLocationType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PickUserLocationType.php @@ -16,10 +16,9 @@ use Chill\MainBundle\Repository\LocationRepository; use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -class Select2UserLocationType extends AbstractType +class PickUserLocationType extends AbstractType { private LocationRepository $locationRepository; @@ -31,10 +30,10 @@ class Select2UserLocationType extends AbstractType $this->locationRepository = $locationRepository; } - public function buildForm(FormBuilderInterface $builder, array $options) + public function configureOptions(OptionsResolver $resolver) { - $builder - ->add('currentLocation', EntityType::class, [ + $resolver + ->setDefaults([ 'class' => Location::class, 'choices' => $this->locationRepository->findByPublicLocations(), 'choice_label' => function (Location $entity) { @@ -44,24 +43,15 @@ class Select2UserLocationType extends AbstractType }, 'placeholder' => 'Pick a location', 'required' => false, - 'label' => $options['label'], - 'label_attr' => $options['label_attr'], - 'multiple' => $options['multiple'], 'attr' => ['class' => 'select2'], - ]); - } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setDefault('label', 'Current location') - ->setDefault('label_attr', []) - ->setDefault('multiple', false) + 'label' => 'Current location', + 'multiple' => false, + ]) ->setAllowedTypes('multiple', ['bool']); } - public function getBlockPrefix(): string + public function getParent(): string { - return 'select2_user_location_type'; + return EntityType::class; } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2LocationTypeType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2LocationTypeType.php deleted file mode 100644 index 783ec4e5c..000000000 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2LocationTypeType.php +++ /dev/null @@ -1,59 +0,0 @@ -translatableStringHelper = $translatableStringHelper; - } - - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->add('locationtype', EntityType::class, [ - 'class' => LocationType::class, - 'choice_label' => function (LocationType $type) { - return $this->translatableStringHelper->localize($type->getTitle()); - }, - 'placeholder' => 'Pick a location type', - 'required' => false, - 'label' => $options['label'], - 'label_attr' => $options['label_attr'], - 'multiple' => $options['multiple'], - 'attr' => ['class' => 'select2'], - ]); - } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setDefault('label', 'Location type') - ->setDefault('label_attr', []) - ->setDefault('multiple', false) - ->setAllowedTypes('multiple', ['bool']); - } - - public function getBlockPrefix(): string - { - return 'select2_location_type_type'; - } -} diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php new file mode 100644 index 000000000..bf6a5d172 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -0,0 +1,24 @@ +add('currentLocation', PickUserLocationType::class); + } +} diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml index 34f5d1802..4408a7223 100644 --- a/src/Bundle/ChillMainBundle/config/services/form.yaml +++ b/src/Bundle/ChillMainBundle/config/services/form.yaml @@ -130,14 +130,6 @@ services: autowire: true autoconfigure: true - Chill\MainBundle\Form\Type\Select2UserLocationType: - autowire: true - autoconfigure: true - - Chill\MainBundle\Form\Type\Select2LocationTypeType: - autowire: true - autoconfigure: true - Chill\MainBundle\Form\Type\LocationFormType: ~ Chill\MainBundle\Form\WorkflowStepType: ~ diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php index 1607d385d..29e8a413d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php @@ -228,6 +228,22 @@ class SocialAction return $descendants; } + /** + * @param Collection|SocialAction[] $socialActions + */ + public static function getDescendantsWithThisForActions($socialActions): Collection + { + $unique = []; + + foreach ($socialActions as $action) { + foreach ($action->getDescendantsWithThis() as $child) { + $unique[spl_object_hash($child)] = $child; + } + } + + return new ArrayCollection(array_values($unique)); + } + public function getEvaluations(): Collection { return $this->evaluations; @@ -274,6 +290,11 @@ class SocialAction return $this->title; } + public function hasChildren(): bool + { + return 0 < $this->getChildren()->count(); + } + public function hasParent(): bool { return $this->getParent() instanceof self; @@ -369,6 +390,8 @@ class SocialAction { $this->parent = $parent; + $parent->addChild($this); + return $this; } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php index 06f05c91f..42c8442c1 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php @@ -71,11 +71,17 @@ class SocialIssue $this->socialActions = new ArrayCollection(); } + /** + * @internal use @see{SocialIssue::setParent} instead + * + * @param SocialIssue $child + * + * @return $this + */ public function addChild(self $child): self { if (!$this->children->contains($child)) { $this->children[] = $child; - $child->setParent($this); } return $this; @@ -215,6 +221,22 @@ class SocialIssue return $descendants; } + /** + * @param array|SocialIssue[] $socialIssues + */ + public static function getDescendantsWithThisForIssues(array $socialIssues): Collection + { + $unique = []; + + foreach ($socialIssues as $issue) { + foreach ($issue->getDescendantsWithThis() as $child) { + $unique[spl_object_hash($child)] = $child; + } + } + + return new ArrayCollection(array_values($unique)); + } + public function getId(): ?int { return $this->id; @@ -262,6 +284,11 @@ class SocialIssue return $this->title; } + public function hasChildren(): bool + { + return 0 < $this->getChildren()->count(); + } + public function hasParent(): bool { return null !== $this->parent; @@ -329,6 +356,8 @@ class SocialIssue { $this->parent = $parent; + $parent->addChild($this); + return $this; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php index d289220af..52f875a5e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/AdministrativeLocationFilter.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Form\Type\Select2UserLocationType; +use Chill\MainBundle\Form\Type\PickUserLocationType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\QueryBuilder; @@ -48,11 +48,8 @@ class AdministrativeLocationFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_locations', Select2UserLocationType::class, [ + $builder->add('accepted_locations', PickUserLocationType::class, [ 'label' => 'Accepted locations', - 'label_attr' => [ - //'class' => 'd-none' - ], 'multiple' => true, ]); } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php index c5c37ce21..e3bf77af2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialActionFilter.php @@ -15,10 +15,9 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\PersonBundle\Export\Declarations; +use Chill\PersonBundle\Form\Type\PickSocialActionType; use Chill\PersonBundle\Templating\Entity\SocialActionRender; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use function in_array; @@ -51,17 +50,13 @@ class SocialActionFilter implements FilterInterface $qb->join('acpw.socialAction', 'acpwsocialaction'); } - $where = $qb->getDQLPart('where'); $clause = $qb->expr()->in('acpwsocialaction.id', ':socialactions'); - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('socialactions', $data['accepted_socialactions']); + $qb->andWhere($clause) + ->setParameter( + 'socialactions', + SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions'])->toArray() + ); } public function applyOn(): string @@ -71,26 +66,25 @@ class SocialActionFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_socialactions', EntityType::class, [ - 'class' => SocialAction::class, - 'choice_label' => function (SocialAction $sa) { - return $this->actionRender->renderString($sa, []); - }, + $builder->add('accepted_socialactions', PickSocialActionType::class, [ 'multiple' => true, - 'expanded' => true, ]); } public function describeAction($data, $format = 'string'): array { - $socialactions = []; + $actions = []; - foreach ($data['accepted_socialactions'] as $sa) { - $socialactions[] = $this->actionRender->renderString($sa, []); + $socialactions = $data['accepted_socialactions']; + + foreach ($socialactions as $action) { + $actions[] = $this->actionRender->renderString($action, [ + 'show_and_children' => true, + ]); } return ['Filtered by socialactions: only %socialactions%', [ - '%socialactions%' => implode(', ou ', $socialactions), + '%socialactions%' => implode(', ou ', $actions), ]]; } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php index d896d6395..083c15f91 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingCourseFilters/SocialIssueFilter.php @@ -15,10 +15,9 @@ use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Export\Declarations; +use Chill\PersonBundle\Form\Type\PickSocialIssueType; use Chill\PersonBundle\Templating\Entity\SocialIssueRender; -use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\QueryBuilder; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Contracts\Translation\TranslatorInterface; use function in_array; @@ -55,20 +54,13 @@ class SocialIssueFilter implements FilterInterface $qb->join('acp.socialIssues', 'acpsocialissue'); } - $where = $qb->getDQLPart('where'); $clause = $qb->expr()->in('acpsocialissue.id', ':socialissues'); - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter( - 'socialissues', - $this->addParentIssues($data['accepted_socialissues']) - ); + $qb->andWhere($clause) + ->setParameter( + 'socialissues', + SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues']) + ); } public function applyOn() @@ -78,28 +70,21 @@ class SocialIssueFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { - $builder->add('accepted_socialissues', EntityType::class, [ - 'class' => SocialIssue::class, - 'choice_label' => function ($socialIssue) { - return $this->socialIssueRender->renderString($socialIssue, []); - }, + $builder->add('accepted_socialissues', PickSocialIssueType::class, [ 'multiple' => true, - 'expanded' => true, ]); } - public function describeAction($data, $format = 'string') + public function describeAction($data, $format = 'string'): array { $issues = []; - $socialissues = $this->addParentIssues($data['accepted_socialissues']); + $socialissues = $data['accepted_socialissues']; - foreach ($socialissues as $i) { - if ('null' === $i) { - $issues[] = $this->translator->trans('Not given'); - } else { - $issues[] = $this->socialIssueRender->renderString($i, []); - } + foreach ($socialissues as $issue) { + $issues[] = $this->socialIssueRender->renderString($issue, [ + 'show_and_children' => true, + ]); } return [ @@ -108,44 +93,8 @@ class SocialIssueFilter implements FilterInterface ], ]; } - public function getTitle() + public function getTitle(): string { return 'Filter by social issue'; } - - /** - * "Le filtre retiendra les parcours qui comportent cette problématique, - * ou une problématique parente à celles choisies.". - * - * Add parent of each socialissue selected, and remove duplicates - * - * @param $accepted_issues - */ - private function addParentIssues($accepted_issues): array - { - $array = []; - - foreach ($accepted_issues as $i) { - /** @var SocialIssue $i */ - if ($i->hasParent()) { - $array[] = $i->getParent(); - } - $array[] = $i; - } - - return $this->removeDuplicate($array); - } - - private function removeDuplicate(array $array): array - { - $ids = array_map(static function ($item) { - return $item->getId(); - }, $array); - - $unique_ids = array_unique($ids); - - return array_values( - array_intersect_key($array, $unique_ids) - ); - } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickSocialActionType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickSocialActionType.php new file mode 100644 index 000000000..7c0da43b1 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickSocialActionType.php @@ -0,0 +1,57 @@ +actionRender = $actionRender; + $this->actionRepository = $actionRepository; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults([ + 'class' => SocialAction::class, + 'choices' => $this->actionRepository->findAllActive(), + 'choice_label' => function (SocialAction $sa) { + return $this->actionRender->renderString($sa, []); + }, + 'placeholder' => 'Pick a social action', + 'required' => false, + 'attr' => ['class' => 'select2'], + 'label' => 'Social actions', + 'multiple' => false, + ]) + ->setAllowedTypes('multiple', ['bool']); + } + + public function getParent(): string + { + return EntityType::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickSocialIssueType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickSocialIssueType.php new file mode 100644 index 000000000..e79c17191 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickSocialIssueType.php @@ -0,0 +1,57 @@ +issueRender = $issueRender; + $this->issueRepository = $issueRepository; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults([ + 'class' => SocialIssue::class, + 'choices' => $this->issueRepository->findAllActive(), + 'choice_label' => function (SocialIssue $si) { + return $this->issueRender->renderString($si, []); + }, + 'placeholder' => 'Pick a social issue', + 'required' => false, + 'attr' => ['class' => 'select2'], + 'label' => 'Social issues', + 'multiple' => false, + ]) + ->setAllowedTypes('multiple', ['bool']); + } + + public function getParent(): string + { + return EntityType::class; + } +} diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php index 052432741..370704aed 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialActionRepository.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\PersonBundle\Repository\SocialWork; use Chill\PersonBundle\Entity\SocialWork\SocialAction; +use DateTime; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; @@ -44,6 +45,14 @@ final class SocialActionRepository implements ObjectRepository return $this->repository->findAll(); } + /** + * @return array|SocialAction[] + */ + public function findAllActive(): array + { + return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult(); + } + /** * @param mixed|null $limit * @param mixed|null $offset @@ -67,4 +76,16 @@ final class SocialActionRepository implements ObjectRepository { return SocialAction::class; } + + private function buildQueryWithDesactivatedDateCriteria(): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('sa'); + + $qb->where('sa.desactivationDate is null') + ->orWhere('sa.desactivationDate > :now') + ->orderBy('sa.ordering', 'ASC') + ->setParameter('now', new DateTime('now')); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php index 27b4ed4e9..8dd8f6a62 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/SocialIssueRepository.php @@ -12,8 +12,10 @@ declare(strict_types=1); namespace Chill\PersonBundle\Repository\SocialWork; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; +use DateTime; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; final class SocialIssueRepository implements ObjectRepository @@ -38,6 +40,14 @@ final class SocialIssueRepository implements ObjectRepository return $this->repository->findAll(); } + /** + * @return array|SocialIssue[] + */ + public function findAllActive(): array + { + return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult(); + } + /** * @param mixed|null $limit * @param mixed|null $offset @@ -61,4 +71,16 @@ final class SocialIssueRepository implements ObjectRepository { return SocialIssue::class; } + + private function buildQueryWithDesactivatedDateCriteria(): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('si'); + + $qb->where('si.desactivationDate is null') + ->orWhere('si.desactivationDate > :now') + ->orderBy('si.ordering', 'ASC') + ->setParameter('now', new DateTime('now')); + + return $qb; + } } diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php index f2ee13fc1..bfe49c0a4 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialActionRender.php @@ -15,16 +15,20 @@ use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Symfony\Component\Templating\EngineInterface; - +use Symfony\Contracts\Translation\TranslatorInterface; use function array_merge; use function array_reverse; use function implode; class SocialActionRender implements ChillEntityRenderInterface { + public const AND_CHILDREN_MENTION = 'show_and_children_mention'; + public const DEFAULT_ARGS = [ self::SEPARATOR_KEY => ' > ', self::NO_BADGE => false, + self::SHOW_AND_CHILDREN => false, + self::AND_CHILDREN_MENTION => 'social_action.and children', ]; /** @@ -34,14 +38,26 @@ class SocialActionRender implements ChillEntityRenderInterface public const SEPARATOR_KEY = 'default.separator'; + /** + * Show a mention "and children" on each SocialAction, if the social action + * has at least one child. + */ + public const SHOW_AND_CHILDREN = 'show_and_children'; + private EngineInterface $engine; private TranslatableStringHelper $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) - { + private TranslatorInterface $translator; + + public function __construct( + TranslatableStringHelper $translatableStringHelper, + EngineInterface $engine, + TranslatorInterface $translator + ) { $this->translatableStringHelper = $translatableStringHelper; $this->engine = $engine; + $this->translator = $translator; } public function renderBox($socialAction, array $options): string @@ -72,7 +88,13 @@ class SocialActionRender implements ChillEntityRenderInterface $titles = array_reverse($titles); - return implode($options[self::SEPARATOR_KEY], $titles); + $title = implode($options[self::SEPARATOR_KEY], $titles); + + if ($options[self::SHOW_AND_CHILDREN] && $socialAction->hasChildren()) { + $title .= ' (' . $this->translator->trans($options[self::AND_CHILDREN_MENTION]) . ')'; + } + + return $title; } public function supports($entity, array $options): bool diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php index 014b23c8e..62d17f47e 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/SocialIssueRender.php @@ -15,26 +15,42 @@ use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Symfony\Component\Templating\EngineInterface; - +use Symfony\Contracts\Translation\TranslatorInterface; use function array_reverse; use function implode; final class SocialIssueRender implements ChillEntityRenderInterface { + public const AND_CHILDREN_MENTION = 'show_and_children_mention'; + public const DEFAULT_ARGS = [ self::SEPARATOR_KEY => ' > ', + self::SHOW_AND_CHILDREN => false, + self::AND_CHILDREN_MENTION => 'social_issue.and children', ]; public const SEPARATOR_KEY = 'default.separator'; + /** + * Show a mention "and children" on each SocialIssue, if the social issue + * has at least one child. + */ + public const SHOW_AND_CHILDREN = 'show_and_children'; + private EngineInterface $engine; private TranslatableStringHelper $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine) - { + private TranslatorInterface $translator; + + public function __construct( + TranslatableStringHelper $translatableStringHelper, + EngineInterface $engine, + TranslatorInterface $translator + ) { $this->translatableStringHelper = $translatableStringHelper; $this->engine = $engine; + $this->translator = $translator; } /** @@ -78,7 +94,13 @@ final class SocialIssueRender implements ChillEntityRenderInterface $titles = array_reverse($titles); - return implode($options[self::SEPARATOR_KEY], $titles); + $title = implode($options[self::SEPARATOR_KEY], $titles); + + if ($options[self::SHOW_AND_CHILDREN] && $socialIssue->hasChildren()) { + $title .= ' (' . $this->translator->trans($options[self::AND_CHILDREN_MENTION]) . ')'; + } + + return $title; } public function supports($entity, array $options): bool diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialActionTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialActionTest.php new file mode 100644 index 000000000..2dcfa6b11 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialActionTest.php @@ -0,0 +1,51 @@ +setParent($parentA); + $grandChildA = (new SocialAction())->setParent($childA); + $grandGrandChildA = (new SocialAction())->setParent($grandChildA); + $unrelatedA = new SocialAction(); + + $parentB = new SocialAction(); + $childB = (new SocialAction())->setParent($parentB); + $grandChildB = (new SocialAction())->setParent($childB); + $grandGrandChildB = (new SocialAction())->setParent($grandChildB); + $unrelatedB = new SocialAction(); + + $actual = SocialAction::getDescendantsWithThisForActions([$parentA, $parentB]); + + $this->assertContains($parentA, $actual); + $this->assertContains($parentB, $actual); + $this->assertContains($childA, $actual); + $this->assertContains($childB, $actual); + $this->assertContains($grandChildA, $actual); + $this->assertContains($grandChildB, $actual); + $this->assertContains($grandGrandChildA, $actual); + $this->assertContains($grandGrandChildB, $actual); + $this->assertCount(8, $actual); + $this->assertNotContains($unrelatedA, $actual); + $this->assertNotContains($unrelatedB, $actual); + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php index edc1e5474..b846ae5f4 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/SocialWork/SocialIssueTest.php @@ -55,6 +55,35 @@ final class SocialIssueTest extends TestCase $this->assertCount(0, $unrelated->getAncestors(false)); } + public function testGetDescendantsWithThisForIssues() + { + $parentA = new SocialIssue(); + $childA = (new SocialIssue())->setParent($parentA); + $grandChildA = (new SocialIssue())->setParent($childA); + $grandGrandChildA = (new SocialIssue())->setParent($grandChildA); + $unrelatedA = new SocialIssue(); + + $parentB = new SocialIssue(); + $childB = (new SocialIssue())->setParent($parentB); + $grandChildB = (new SocialIssue())->setParent($childB); + $grandGrandChildB = (new SocialIssue())->setParent($grandChildB); + $unrelatedB = new SocialIssue(); + + $actual = SocialIssue::getDescendantsWithThisForIssues([$parentA, $parentB]); + + $this->assertContains($parentA, $actual); + $this->assertContains($parentB, $actual); + $this->assertContains($childA, $actual); + $this->assertContains($childB, $actual); + $this->assertContains($grandChildA, $actual); + $this->assertContains($grandChildB, $actual); + $this->assertContains($grandGrandChildA, $actual); + $this->assertContains($grandGrandChildB, $actual); + $this->assertCount(8, $actual); + $this->assertNotContains($unrelatedA, $actual); + $this->assertNotContains($unrelatedB, $actual); + } + public function testIsDescendantOf() { $parent = new SocialIssue(); diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index 76fb12d18..ede58394c 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -205,9 +205,11 @@ Resources: Interlocuteurs privilégiés Any requestor to this accompanying course: Aucun demandeur pour ce parcours Social action: Action d'accompagnement Social actions: Actions d'accompagnement +Pick a social action: Choisir une action d'accompagnement Last social actions: Les dernières actions d'accompagnement Social issue: Problématique sociale Social issues: Problématiques sociales +Pick a social issue: Choisir une problématique sociale Last events on accompanying course: Dernières actions de suivi Edit & activate accompanying course: Modifier et valider See accompanying periods: Voir toutes les périodes d'accompagnement @@ -953,6 +955,7 @@ export: Group course by referrer's scope: Grouper les parcours par service du référent Computation date for referrer: Date à laquelle le référent était actif Referrer's scope: Service du référent de parcours + duration: day: Durée du parcours en jours week: Durée du parcours en semaines @@ -965,3 +968,8 @@ export: by_referrer: Computation date for referrer: Date à laquelle le référent était actif +social_action: + and children: et dérivés + +social_issue: + and children: et dérivés