From c059b7700e63e9612ad6aad7a2b11d4e20ac07b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 21 Sep 2022 11:10:35 +0200 Subject: [PATCH] Improve label for aliases in "Filter by Activity" and use of new-style EntityRepository for ActivityType * [activity][export] Feature: improve label for aliases in "Filter by activity type" * [activity][export] DX/Feature: use of an `ActivityTypeRepositoryInterface` instead of the old-style EntityRepository --- CHANGELOG.md | 2 + .../Controller/ActivityController.php | 6 +- .../Entity/ActivityType.php | 5 ++ .../Aggregator/ActivityTypeAggregator.php | 6 +- .../Filter/ACPFilters/ActivityTypeFilter.php | 42 ++++++-------- .../Export/Filter/ActivityTypeFilter.php | 34 ++++++----- .../Form/Type/TranslatableActivityType.php | 20 ++----- .../Repository/ActivityTypeRepository.php | 58 ++++++++++++++++--- .../ActivityTypeRepositoryInterface.php | 15 +++++ 9 files changed, 121 insertions(+), 67 deletions(-) create mode 100644 src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepositoryInterface.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f4e0ab7f0..1a1fd7210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to * [person][export] Fixed: rename the alias for `accompanying_period` to `acp` in filter associated with person +* [activity][export] Feature: improve label for aliases in "Filter by activity type" +* [activity][export] DX/Feature: use of an `ActivityTypeRepositoryInterface` instead of the old-style EntityRepository ## Test releases diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 2c380ad52..fa6cde7c1 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -17,7 +17,7 @@ use Chill\ActivityBundle\Form\ActivityType; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository; -use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Repository\LocationRepository; @@ -55,7 +55,7 @@ final class ActivityController extends AbstractController private ActivityTypeCategoryRepository $activityTypeCategoryRepository; - private ActivityTypeRepository $activityTypeRepository; + private ActivityTypeRepositoryInterface $activityTypeRepository; private CenterResolverManagerInterface $centerResolver; @@ -75,7 +75,7 @@ final class ActivityController extends AbstractController public function __construct( ActivityACLAwareRepositoryInterface $activityACLAwareRepository, - ActivityTypeRepository $activityTypeRepository, + ActivityTypeRepositoryInterface $activityTypeRepository, ActivityTypeCategoryRepository $activityTypeCategoryRepository, PersonRepository $personRepository, ThirdPartyRepository $thirdPartyRepository, diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index 845b31ca2..a2b15ee23 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -516,6 +516,11 @@ class ActivityType return $this->userVisible; } + public function hasCategory(): bool + { + return null !== $this->getCategory(); + } + /** * Is active * return true if the type is active. diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php index 5c285ca3e..cada50387 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; use Chill\ActivityBundle\Export\Declarations; -use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Closure; @@ -25,12 +25,12 @@ class ActivityTypeAggregator implements AggregatorInterface { public const KEY = 'activity_type_aggregator'; - protected ActivityTypeRepository $activityTypeRepository; + protected ActivityTypeRepositoryInterface $activityTypeRepository; protected TranslatableStringHelperInterface $translatableStringHelper; public function __construct( - ActivityTypeRepository $activityTypeRepository, + ActivityTypeRepositoryInterface $activityTypeRepository, TranslatableStringHelperInterface $translatableStringHelper ) { $this->activityTypeRepository = $activityTypeRepository; diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php index 7c0b202bd..d17a6af99 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ACPFilters/ActivityTypeFilter.php @@ -13,8 +13,9 @@ namespace Chill\ActivityBundle\Export\Filter\ACPFilters; use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Entity\ActivityType; +use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Chill\PersonBundle\Export\Declarations; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Andx; @@ -22,15 +23,17 @@ use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\FormBuilderInterface; -/** - * TODO merge with ActivityTypeFilter in ChillActivity (!?). - */ class ActivityTypeFilter implements FilterInterface { - private TranslatableStringHelper $translatableStringHelper; + private ActivityTypeRepositoryInterface $activityTypeRepository; - public function __construct(TranslatableStringHelper $translatableStringHelper) - { + private TranslatableStringHelperInterface $translatableStringHelper; + + public function __construct( + ActivityTypeRepositoryInterface $activityTypeRepository, + TranslatableStringHelperInterface $translatableStringHelper + ) { + $this->activityTypeRepository = $activityTypeRepository; $this->translatableStringHelper = $translatableStringHelper; } @@ -45,21 +48,10 @@ class ActivityTypeFilter implements FilterInterface $qb->join(Activity::class, 'activity', Expr\Join::WITH, 'activity.accompanyingPeriod = acp'); } - if (!in_array('acttype', $qb->getAllAliases(), true)) { - $qb->join('activity.activityType', 'acttype'); - } + $clause = $qb->expr()->in('activity.activityType', ':selected_activity_types'); - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->in('acttype.id', ':activitytypes'); - - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('activitytypes', $data['accepted_activitytypes']); + $qb->andWhere($clause); + $qb->setParameter('selected_activity_types', $data['types']); } public function applyOn() @@ -71,8 +63,12 @@ class ActivityTypeFilter implements FilterInterface { $builder->add('accepted_activitytypes', EntityType::class, [ 'class' => ActivityType::class, + 'choices' => $this->activityTypeRepository->findAllActive(), 'choice_label' => function (ActivityType $aty) { - return $this->translatableStringHelper->localize($aty->getName()); + return + ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '') + . + $this->translatableStringHelper->localize($aty->getName()); }, 'multiple' => true, 'expanded' => true, @@ -88,7 +84,7 @@ class ActivityTypeFilter implements FilterInterface } return ['Filtered by activity types: only %activitytypes%', [ - '%activitytypes%' => implode(', ou ', $types), + '%activitytypes%' => implode(', ', $types), ]]; } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php index 77d887fdf..7442fabb7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php @@ -13,7 +13,7 @@ namespace Chill\ActivityBundle\Export\Filter; use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Export\Declarations; -use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; @@ -28,13 +28,13 @@ use function count; class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInterface { - protected ActivityTypeRepository $activityTypeRepository; + protected ActivityTypeRepositoryInterface $activityTypeRepository; protected TranslatableStringHelperInterface $translatableStringHelper; public function __construct( TranslatableStringHelperInterface $translatableStringHelper, - ActivityTypeRepository $activityTypeRepository + ActivityTypeRepositoryInterface $activityTypeRepository ) { $this->translatableStringHelper = $translatableStringHelper; $this->activityTypeRepository = $activityTypeRepository; @@ -47,16 +47,9 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter public function alterQuery(QueryBuilder $qb, $data) { - $where = $qb->getDQLPart('where'); $clause = $qb->expr()->in('activity.activityType', ':selected_activity_types'); - if ($where instanceof Expr\Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); + $qb->andWhere($clause); $qb->setParameter('selected_activity_types', $data['types']); } @@ -68,11 +61,26 @@ class ActivityTypeFilter implements ExportElementValidatedInterface, FilterInter public function buildForm(FormBuilderInterface $builder) { $builder->add('types', EntityType::class, [ + 'choices' => $this->activityTypeRepository->findAllActive(), 'class' => ActivityType::class, - 'choice_label' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getName()), - 'group_by' => fn (ActivityType $type) => $this->translatableStringHelper->localize($type->getCategory()->getName()), + 'choice_label' => function (ActivityType $aty) { + return + ($aty->hasCategory() ? $this->translatableStringHelper->localize($aty->getCategory()->getName()) . ' > ' : '') + . + $this->translatableStringHelper->localize($aty->getName()); + }, + 'group_by' => function (ActivityType $type) { + if (!$type->hasCategory()) { + return null; + } + + return $this->translatableStringHelper->localize($type->getCategory()->getName()); + }, 'multiple' => true, 'expanded' => false, + 'attr' => [ + 'class' => 'select2' + ] ]); } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php index dc6328709..8140043a4 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php @@ -12,7 +12,7 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Form\Type; use Chill\ActivityBundle\Entity\ActivityType; -use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\ActivityBundle\Repository\ActivityTypeRepositoryInterface; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\QueryBuilder; @@ -23,37 +23,25 @@ use Symfony\Component\OptionsResolver\OptionsResolver; class TranslatableActivityType extends AbstractType { - protected ActivityTypeRepository $activityTypeRepository; + protected ActivityTypeRepositoryInterface $activityTypeRepository; protected TranslatableStringHelperInterface $translatableStringHelper; public function __construct( TranslatableStringHelperInterface $helper, - ActivityTypeRepository $activityTypeRepository + ActivityTypeRepositoryInterface $activityTypeRepository ) { $this->translatableStringHelper = $helper; $this->activityTypeRepository = $activityTypeRepository; } - public function buildForm(FormBuilderInterface $builder, array $options) - { - /** @var QueryBuilder $qb */ - $qb = $options['query_builder']; - - if (true === $options['active_only']) { - $qb->where($qb->expr()->eq('at.active', ':active')); - $qb->setParameter('active', true, Types::BOOLEAN); - } - } - public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults( [ 'class' => ActivityType::class, 'active_only' => true, - 'query_builder' => $this->activityTypeRepository - ->createQueryBuilder('at'), + 'choices' => $this->activityTypeRepository->findAllActive(), 'choice_label' => function (ActivityType $type) { return $this->translatableStringHelper->localize($type->getName()); }, diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepository.php index 735b70054..aee3706cf 100644 --- a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepository.php +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepository.php @@ -13,18 +13,58 @@ namespace Chill\ActivityBundle\Repository; use Chill\ActivityBundle\Entity\ActivityType; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; use Doctrine\Persistence\ManagerRegistry; +use UnexpectedValueException; -/** - * @method ActivityType|null find($id, $lockMode = null, $lockVersion = null) - * @method ActivityType|null findOneBy(array $criteria, array $orderBy = null) - * @method ActivityType[] findAll() - * @method ActivityType[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) - */ -class ActivityTypeRepository extends ServiceEntityRepository +final class ActivityTypeRepository implements ActivityTypeRepositoryInterface { - public function __construct(ManagerRegistry $registry) + private EntityRepository $repository; + + public function __construct(EntityManagerInterface $em) { - parent::__construct($registry, ActivityType::class); + $this->repository = $em->getRepository(ActivityType::class); } + + /** + * @return array|ActivityType[] + */ + public function findAllActive(): array + { + return $this->findBy(['active' => true]); + } + + public function find($id): ?ActivityType + { + return $this->repository->find($id); + } + + /** + * @return array|ActivityType[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return array|ActivityType[] + */ + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?ActivityType + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return ActivityType::class; + } + + } diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepositoryInterface.php b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepositoryInterface.php new file mode 100644 index 000000000..533798e5e --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeRepositoryInterface.php @@ -0,0 +1,15 @@ +