review: fix stuffs on socialAction and socialIssue filters:

* filters call static entity method
* add renderString option to manage add_children
* add tests on new entity method getDescendantsWithThisFor..()
* rename function in repository
* rename 'Select2..' classes by 'Pick..' and replace all occurences
This commit is contained in:
Mathieu Jaumotte 2022-10-17 09:52:29 +02:00
parent 71f989f00e
commit 32ddc5465c
22 changed files with 244 additions and 151 deletions

View File

@ -13,7 +13,8 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\PersonBundle\Form\Type\Select2SocialActionType; use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Form\Type\PickSocialActionType;
use Chill\PersonBundle\Templating\Entity\SocialActionRender; use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -41,8 +42,10 @@ class BySocialActionFilter implements FilterInterface
$clause = $qb->expr()->in('actsocialaction.id', ':socialactions'); $clause = $qb->expr()->in('actsocialaction.id', ':socialactions');
$qb ->andWhere($clause) $qb->andWhere($clause)
->setParameter('socialactions', $data['accepted_socialactions']); ->setParameter('socialactions',
SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions'])
);
} }
public function applyOn(): string public function applyOn(): string
@ -52,7 +55,7 @@ class BySocialActionFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_socialactions', Select2SocialActionType::class, [ $builder->add('accepted_socialactions', PickSocialActionType::class, [
'multiple' => true 'multiple' => true
]); ]);
} }
@ -61,8 +64,10 @@ class BySocialActionFilter implements FilterInterface
{ {
$actions = []; $actions = [];
foreach ($data['accepted_socialactions'] as $sa) { foreach ($data['accepted_socialactions'] as $action) {
$actions[] = $this->actionRender->renderString($sa, []); $actions[] = $this->actionRender->renderString($action, [
'show_and_children' => true,
]);
} }
return ['Filtered activity by linked socialaction: only %actions%', [ return ['Filtered activity by linked socialaction: only %actions%', [

View File

@ -13,7 +13,8 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\PersonBundle\Form\Type\Select2SocialIssueType; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Form\Type\PickSocialIssueType;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -41,8 +42,10 @@ class BySocialIssueFilter implements FilterInterface
$clause = $qb->expr()->in('actsocialissue.id', ':socialissues'); $clause = $qb->expr()->in('actsocialissue.id', ':socialissues');
$qb ->andWhere($clause) $qb->andWhere($clause)
->setParameter('socialissues', $data['accepted_socialissues']); ->setParameter('socialissues',
SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues'])
);
} }
public function applyOn(): string public function applyOn(): string
@ -52,7 +55,7 @@ class BySocialIssueFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_socialissues', Select2SocialIssueType::class, [ $builder->add('accepted_socialissues', PickSocialIssueType::class, [
'multiple' => true 'multiple' => true
]); ]);
} }
@ -61,8 +64,10 @@ class BySocialIssueFilter implements FilterInterface
{ {
$issues = []; $issues = [];
foreach ($data['accepted_socialissues'] as $si) { foreach ($data['accepted_socialissues'] as $issue) {
$issues[] = $this->issueRender->renderString($si, []); $issues[] = $this->issueRender->renderString($issue, [
'show_and_children' => true,
]);
} }
return ['Filtered activity by linked socialissue: only %issues%', [ return ['Filtered activity by linked socialissue: only %issues%', [

View File

@ -13,7 +13,7 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters;
use Chill\ActivityBundle\Export\Declarations; use Chill\ActivityBundle\Export\Declarations;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Select2LocationTypeType; use Chill\MainBundle\Form\Type\PickLocationTypeType;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Andx; use Doctrine\ORM\Query\Expr\Andx;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@ -60,7 +60,7 @@ class LocationTypeFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_locationtype', Select2LocationTypeType::class, [ $builder->add('accepted_locationtype', PickLocationTypeType::class, [
'multiple' => true, 'multiple' => true,
//'label' => false, //'label' => false,
]); ]);

View File

@ -17,7 +17,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class Select2LocationTypeType extends AbstractType class PickLocationTypeType extends AbstractType
{ {
private TranslatableStringHelper $translatableStringHelper; private TranslatableStringHelper $translatableStringHelper;

View File

@ -18,7 +18,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class Select2UserLocationType extends AbstractType class PickUserLocationType extends AbstractType
{ {
private LocationRepository $locationRepository; private LocationRepository $locationRepository;

View File

@ -11,7 +11,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Form; namespace Chill\MainBundle\Form;
use Chill\MainBundle\Form\Type\Select2UserLocationType; use Chill\MainBundle\Form\Type\PickUserLocationType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -20,7 +20,7 @@ class UserCurrentLocationType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder->add('currentLocation', Select2UserLocationType::class); $builder->add('currentLocation', PickUserLocationType::class);
} }
} }

View File

@ -130,14 +130,6 @@ services:
autowire: true autowire: true
autoconfigure: 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\Type\LocationFormType: ~
Chill\MainBundle\Form\WorkflowStepType: ~ Chill\MainBundle\Form\WorkflowStepType: ~

View File

@ -227,6 +227,23 @@ class SocialAction
return $descendants; return $descendants;
} }
/**
* @param Collection|SocialAction[] $socialActions
* @return Collection
*/
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 public function getEvaluations(): Collection
{ {
return $this->evaluations; return $this->evaluations;
@ -278,6 +295,11 @@ class SocialAction
return $this->getParent() instanceof self; return $this->getParent() instanceof self;
} }
public function hasChildren(): bool
{
return 0 < $this->getChildren()->count();
}
/** /**
* Recursive method which return true if the current $action * Recursive method which return true if the current $action
* is a descendant of the $action given in parameter. * is a descendant of the $action given in parameter.

View File

@ -215,6 +215,23 @@ class SocialIssue
return $descendants; return $descendants;
} }
/**
* @param Collection|SocialIssue[] $socialIssues
* @return Collection
*/
public static function getDescendantsWithThisForIssues(Collection $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 public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -267,6 +284,11 @@ class SocialIssue
return null !== $this->parent; return null !== $this->parent;
} }
public function hasChildren(): bool
{
return 0 < $this->getChildren()->count();
}
/** /**
* Recursive method which return true if the current $issue is a descendant * Recursive method which return true if the current $issue is a descendant
* of the $issue given in parameter. * of the $issue given in parameter.

View File

@ -12,7 +12,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters; namespace Chill\PersonBundle\Export\Filter\AccompanyingCourseFilters;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Form\Type\Select2UserLocationType; use Chill\MainBundle\Form\Type\PickUserLocationType;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
@ -48,7 +48,7 @@ class AdministrativeLocationFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_locations', Select2UserLocationType::class, [ $builder->add('accepted_locations', PickUserLocationType::class, [
'label' => 'Accepted locations', 'label' => 'Accepted locations',
'label_attr' => [ 'label_attr' => [
//'class' => 'd-none' //'class' => 'd-none'

View File

@ -15,7 +15,7 @@ use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Form\Type\Select2SocialActionType; use Chill\PersonBundle\Form\Type\PickSocialActionType;
use Chill\PersonBundle\Templating\Entity\SocialActionRender; use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -23,10 +23,10 @@ use function in_array;
class SocialActionFilter implements FilterInterface class SocialActionFilter implements FilterInterface
{ {
private SocialActionRender $actionRender;
private TranslatableStringHelper $translatableStringHelper; private TranslatableStringHelper $translatableStringHelper;
private SocialActionRender $actionRender;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
SocialActionRender $actionRender SocialActionRender $actionRender
@ -52,9 +52,9 @@ class SocialActionFilter implements FilterInterface
$clause = $qb->expr()->in('acpwsocialaction.id', ':socialactions'); $clause = $qb->expr()->in('acpwsocialaction.id', ':socialactions');
$qb ->andWhere($clause) $qb->andWhere($clause)
->setParameter('socialactions', ->setParameter('socialactions',
$this->addDescendantsActions($data['accepted_socialactions']) SocialAction::getDescendantsWithThisForActions($data['accepted_socialactions'])->toArray()
); );
} }
@ -65,7 +65,7 @@ class SocialActionFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_socialactions', Select2SocialActionType::class, [ $builder->add('accepted_socialactions', PickSocialActionType::class, [
'multiple' => true, 'multiple' => true,
]); ]);
} }
@ -77,7 +77,9 @@ class SocialActionFilter implements FilterInterface
$socialactions = $data['accepted_socialactions']; $socialactions = $data['accepted_socialactions'];
foreach ($socialactions as $action) { foreach ($socialactions as $action) {
$actions[] = $this->renderAction($action); $actions[] = $this->actionRender->renderString($action, [
'show_and_children' => true,
]);
} }
return ['Filtered by socialactions: only %socialactions%', [ return ['Filtered by socialactions: only %socialactions%', [
@ -89,45 +91,4 @@ class SocialActionFilter implements FilterInterface
{ {
return 'Filter by socialaction'; return 'Filter by socialaction';
} }
private function addDescendantsActions($accepted_socialactions): array
{
$array = [];
foreach ($accepted_socialactions as $action) {
/** @var SocialAction $action */
$array[] = $action;
if (!$action->hasParent()) {
$array = array_merge($array, $action->getDescendants()->toArray());
}
}
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)
);
}
private function renderAction(SocialAction $action): string
{
$render_str = $this->actionRender->renderString($action, []);
if (!$action->hasParent()) {
if (count($action->getDescendants()) > 0) {
return $render_str . " (et dérivés)";
}
}
return $render_str;
}
} }

View File

@ -15,7 +15,7 @@ use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Form\Type\Select2SocialIssueType; use Chill\PersonBundle\Form\Type\PickSocialIssueType;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@ -56,9 +56,9 @@ class SocialIssueFilter implements FilterInterface
$clause = $qb->expr()->in('acpsocialissue.id', ':socialissues'); $clause = $qb->expr()->in('acpsocialissue.id', ':socialissues');
$qb ->andWhere($clause) $qb->andWhere($clause)
->setParameter('socialissues', ->setParameter('socialissues',
$this->addDescendantsIssues($data['accepted_socialissues']) SocialIssue::getDescendantsWithThisForIssues($data['accepted_socialissues'])
); );
} }
@ -69,7 +69,7 @@ class SocialIssueFilter implements FilterInterface
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('accepted_socialissues', Select2SocialIssueType::class, [ $builder->add('accepted_socialissues', PickSocialIssueType::class, [
'multiple' => true, 'multiple' => true,
]); ]);
} }
@ -80,14 +80,10 @@ class SocialIssueFilter implements FilterInterface
$socialissues = $data['accepted_socialissues']; $socialissues = $data['accepted_socialissues'];
foreach ($socialissues as $si) { foreach ($socialissues as $issue) {
/** @var SocialIssue $si */ $issues[] = $this->socialIssueRender->renderString($issue, [
if (null === $si) { 'show_and_children' => true,
$issues[] = $this->translator->trans('Not given'); ]);
} else {
$issues[] = $this->renderIssue($si);
}
} }
return [ return [
@ -100,45 +96,4 @@ class SocialIssueFilter implements FilterInterface
{ {
return 'Filter by social issue'; return 'Filter by social issue';
} }
private function addDescendantsIssues($accepted_socialissues): array
{
$array = [];
foreach ($accepted_socialissues as $si) {
/** @var SocialIssue $si */
$array[] = $si;
if (!$si->hasParent()) {
$array = array_merge($array, $si->getDescendants()->toArray());
}
}
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)
);
}
private function renderIssue(SocialIssue $si): string
{
$render_str = $this->socialIssueRender->renderString($si, []);
if (!$si->hasParent()) {
if (count($si->getDescendants()) > 0) {
return $render_str . " (et dérivés)";
}
}
return $render_str;
}
} }

View File

@ -18,7 +18,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class Select2SocialActionType extends AbstractType class PickSocialActionType extends AbstractType
{ {
private SocialActionRender $actionRender; private SocialActionRender $actionRender;
@ -37,7 +37,7 @@ class Select2SocialActionType extends AbstractType
$resolver $resolver
->setDefaults([ ->setDefaults([
'class' => SocialAction::class, 'class' => SocialAction::class,
'choices' => $this->actionRepository->findActionsNotDesactivated(), 'choices' => $this->actionRepository->findAllActive(),
'choice_label' => function (SocialAction $sa) { 'choice_label' => function (SocialAction $sa) {
return $this->actionRender->renderString($sa, []); return $this->actionRender->renderString($sa, []);
}, },

View File

@ -18,7 +18,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
class Select2SocialIssueType extends AbstractType class PickSocialIssueType extends AbstractType
{ {
private SocialIssueRender $issueRender; private SocialIssueRender $issueRender;
@ -37,7 +37,7 @@ class Select2SocialIssueType extends AbstractType
$resolver $resolver
->setDefaults([ ->setDefaults([
'class' => SocialIssue::class, 'class' => SocialIssue::class,
'choices' => $this->issueRepository->findIssuesNotDesactivated(), 'choices' => $this->issueRepository->findAllActive(),
'choice_label' => function (SocialIssue $si) { 'choice_label' => function (SocialIssue $si) {
return $this->issueRender->renderString($si, []); return $this->issueRender->renderString($si, []);
}, },

View File

@ -68,7 +68,10 @@ final class SocialActionRepository implements ObjectRepository
return SocialAction::class; return SocialAction::class;
} }
public function findActionsNotDesactivated(): array /**
* @return array|SocialAction[]
*/
public function findAllActive(): array
{ {
return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult(); return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult();
} }

View File

@ -63,7 +63,10 @@ final class SocialIssueRepository implements ObjectRepository
return SocialIssue::class; return SocialIssue::class;
} }
public function findIssuesNotDesactivated(): array /**
* @return array|SocialIssue[]
*/
public function findAllActive(): array
{ {
return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult(); return $this->buildQueryWithDesactivatedDateCriteria()->getQuery()->getResult();
} }

View File

@ -15,7 +15,7 @@ use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\SocialWork\SocialAction; use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Symfony\Component\Templating\EngineInterface; use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge; use function array_merge;
use function array_reverse; use function array_reverse;
use function implode; use function implode;
@ -25,6 +25,8 @@ class SocialActionRender implements ChillEntityRenderInterface
public const DEFAULT_ARGS = [ public const DEFAULT_ARGS = [
self::SEPARATOR_KEY => ' > ', self::SEPARATOR_KEY => ' > ',
self::NO_BADGE => false, self::NO_BADGE => false,
self::SHOW_AND_CHILDREN => false,
self::AND_CHILDREN_MENTION => 'social_action.and children',
]; ];
/** /**
@ -34,14 +36,28 @@ class SocialActionRender implements ChillEntityRenderInterface
public const SEPARATOR_KEY = 'default.separator'; 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';
public const AND_CHILDREN_MENTION = 'show_and_children_mention';
private EngineInterface $engine; private EngineInterface $engine;
private TranslatableStringHelper $translatableStringHelper; 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->translatableStringHelper = $translatableStringHelper;
$this->engine = $engine; $this->engine = $engine;
$this->translator = $translator;
} }
public function renderBox($socialAction, array $options): string public function renderBox($socialAction, array $options): string
@ -72,7 +88,13 @@ class SocialActionRender implements ChillEntityRenderInterface
$titles = array_reverse($titles); $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 public function supports($entity, array $options): bool

View File

@ -15,7 +15,7 @@ use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Symfony\Component\Templating\EngineInterface; use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function array_reverse; use function array_reverse;
use function implode; use function implode;
@ -23,18 +23,34 @@ final class SocialIssueRender implements ChillEntityRenderInterface
{ {
public const DEFAULT_ARGS = [ public const DEFAULT_ARGS = [
self::SEPARATOR_KEY => ' > ', self::SEPARATOR_KEY => ' > ',
self::SHOW_AND_CHILDREN => false,
self::AND_CHILDREN_MENTION => 'social_issue.and children',
]; ];
public const SEPARATOR_KEY = 'default.separator'; 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';
public const AND_CHILDREN_MENTION = 'show_and_children_mention';
private EngineInterface $engine; private EngineInterface $engine;
private TranslatableStringHelper $translatableStringHelper; 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->translatableStringHelper = $translatableStringHelper;
$this->engine = $engine; $this->engine = $engine;
$this->translator = $translator;
} }
/** /**
@ -78,7 +94,13 @@ final class SocialIssueRender implements ChillEntityRenderInterface
$titles = array_reverse($titles); $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 public function supports($entity, array $options): bool

View File

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Tests\Entity\SocialWork;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase;
/**
* @internal
* @coversNothing
*/
final class SocialActionTest extends TestCase
{
public function testGetDescendantsWithThisForActions()
{
$parentA = new SocialAction();
$childA = (new SocialAction())->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);
}
}

View File

@ -77,4 +77,33 @@ final class SocialIssueTest extends TestCase
$this->assertFalse($child->isDescendantOf($grandChild)); $this->assertFalse($child->isDescendantOf($grandChild));
} }
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);
}
} }

View File

@ -27,11 +27,3 @@ services:
$config: "%chill_person.accompanying_period_fields%" $config: "%chill_person.accompanying_period_fields%"
tags: tags:
- { name: form.type } - { name: form.type }
Chill\PersonBundle\Form\Type\Select2SocialActionType:
autowire: true
autoconfigure: true
Chill\PersonBundle\Form\Type\Select2SocialIssueType:
autowire: true
autoconfigure: true

View File

@ -951,3 +951,10 @@ export:
Group course by referrer's scope: Grouper les parcours par service du référent 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 Computation date for referrer: Date à laquelle le référent était actif
Referrer's scope: Service du référent de parcours Referrer's scope: Service du référent de parcours
social_action:
and children: et dérivés
social_issue:
and children: et dérivés