diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc54473f..31c3e1b5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to * [person suggest] In widget "add person", improve the pertinence of persons when one of the names starts with the pattern; * [person] do not ask for center any more on person creation * [3party] do not ask for center any more on 3party creation +* [task] Select2 field in task form to allow search for a user (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/167) ## Test releases diff --git a/phpstan-critical.neon b/phpstan-critical.neon index 2e2f778d8..6147f2022 100644 --- a/phpstan-critical.neon +++ b/phpstan-critical.neon @@ -129,4 +129,3 @@ parameters: message: "#^Call to an undefined method Chill\\\\ThirdPartyBundle\\\\Form\\\\Type\\\\PickThirdPartyTypeCategoryType\\:\\:transform\\(\\)\\.$#" count: 1 path: src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php - diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php index 543aa1f6b..5e7e0de21 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityController.php @@ -5,18 +5,21 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Controller; use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\ActivityBundle\Entity\ActivityTypeCategory; use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; +use Chill\ActivityBundle\Repository\ActivityRepository; +use Chill\ActivityBundle\Repository\ActivityTypeCategoryRepository; +use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\ActivityBundle\Security\Authorization\ActivityVoter; -use Chill\MainBundle\Entity\Location; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Repository\LocationRepository; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Privacy\PrivacyEvent; -use Chill\ThirdPartyBundle\Entity\ThirdParty; +use Chill\PersonBundle\Repository\AccompanyingPeriodRepository; +use Chill\PersonBundle\Repository\PersonRepository; +use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; +use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Form\Form; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -30,26 +33,54 @@ use Symfony\Component\Serializer\SerializerInterface; final class ActivityController extends AbstractController { - protected EventDispatcherInterface $eventDispatcher; + private EventDispatcherInterface $eventDispatcher; - protected AuthorizationHelper $authorizationHelper; + private LoggerInterface $logger; - protected LoggerInterface $logger; + private SerializerInterface $serializer; - protected SerializerInterface $serializer; + private ActivityACLAwareRepositoryInterface $activityACLAwareRepository; - protected ActivityACLAwareRepositoryInterface $activityACLAwareRepository; + private ActivityTypeRepository $activityTypeRepository; + + private ThirdPartyRepository $thirdPartyRepository; + + private PersonRepository $personRepository; + + private LocationRepository $locationRepository; + + private EntityManagerInterface $entityManager; + + private ActivityRepository $activityRepository; + + private AccompanyingPeriodRepository $accompanyingPeriodRepository; + + private ActivityTypeCategoryRepository $activityTypeCategoryRepository; public function __construct( ActivityACLAwareRepositoryInterface $activityACLAwareRepository, + ActivityTypeRepository $activityTypeRepository, + ActivityTypeCategoryRepository $activityTypeCategoryRepository, + PersonRepository $personRepository, + ThirdPartyRepository $thirdPartyRepository, + LocationRepository $locationRepository, + ActivityRepository $activityRepository, + AccompanyingPeriodRepository $accompanyingPeriodRepository, + EntityManagerInterface $entityManager, EventDispatcherInterface $eventDispatcher, - AuthorizationHelper $authorizationHelper, LoggerInterface $logger, SerializerInterface $serializer ) { $this->activityACLAwareRepository = $activityACLAwareRepository; + $this->activityTypeRepository = $activityTypeRepository; + $this->activityTypeCategoryRepository = $activityTypeCategoryRepository; + $this->personRepository = $personRepository; + $this->thirdPartyRepository = $thirdPartyRepository; + $this->locationRepository = $locationRepository; + $this->activityRepository = $activityRepository; + $this->accompanyingPeriodRepository = $accompanyingPeriodRepository; + $this->entityManager = $entityManager; $this->eventDispatcher = $eventDispatcher; - $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; $this->serializer = $serializer; } @@ -98,7 +129,6 @@ final class ActivityController extends AbstractController public function selectTypeAction(Request $request): Response { - $em = $this->getDoctrine()->getManager(); $view = null; [$person, $accompanyingPeriod] = $this->getEntity($request); @@ -111,12 +141,17 @@ final class ActivityController extends AbstractController $data = []; - $activityTypeCategories = $em->getRepository(ActivityTypeCategory::class) + $activityTypeCategories = $this + ->activityTypeCategoryRepository ->findBy(['active' => true], ['ordering' => 'ASC']); foreach ($activityTypeCategories as $activityTypeCategory) { - $activityTypes = $em->getRepository(ActivityType::class) - ->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']); + $activityTypes = $this + ->activityTypeRepository + ->findBy( + ['active' => true, 'category' => $activityTypeCategory], + ['ordering' => 'ASC'] + ); $data[] = [ 'activityTypeCategory' => $activityTypeCategory, @@ -139,7 +174,6 @@ final class ActivityController extends AbstractController public function newAction(Request $request): Response { $view = null; - $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); @@ -150,8 +184,7 @@ final class ActivityController extends AbstractController } $activityType_id = $request->get('activityType_id', 0); - $activityType = $em->getRepository(ActivityType::class) - ->find($activityType_id); + $activityType = $this->activityTypeRepository->find($activityType_id); if (isset($activityType) && !$activityType->isActive()) { throw new \InvalidArgumentException('Activity type must be active'); @@ -209,20 +242,20 @@ final class ActivityController extends AbstractController if (array_key_exists('personsId', $activityData)) { foreach($activityData['personsId'] as $personId){ - $concernedPerson = $em->getRepository(Person::class)->find($personId); + $concernedPerson = $this->personRepository->find($personId); $entity->addPerson($concernedPerson); } } if (array_key_exists('professionalsId', $activityData)) { foreach($activityData['professionalsId'] as $professionalsId){ - $professional = $em->getRepository(ThirdParty::class)->find($professionalsId); + $professional = $this->thirdPartyRepository->find($professionalsId); $entity->addThirdParty($professional); } } if (array_key_exists('location', $activityData)) { - $location = $em->getRepository(Location::class)->find($activityData['location']); + $location = $this->locationRepository->find($activityData['location']); $entity->setLocation($location); } @@ -247,8 +280,8 @@ final class ActivityController extends AbstractController ])->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $em->persist($entity); - $em->flush(); + $this->entityManager->persist($entity); + $this->entityManager->flush(); $this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); @@ -277,7 +310,6 @@ final class ActivityController extends AbstractController public function showAction(Request $request, $id): Response { $view = null; - $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); @@ -287,8 +319,7 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:showPerson.html.twig'; } - /** @var Activity $entity */ - $entity = $em->getRepository(Activity::class)->find($id); + $entity = $this->activityRepository->find($id); if (null === $entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); @@ -333,7 +364,6 @@ final class ActivityController extends AbstractController public function editAction($id, Request $request): Response { $view = null; - $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); @@ -343,8 +373,7 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:editPerson.html.twig'; } - /** @var Activity $entity */ - $entity = $em->getRepository(Activity::class)->find($id); + $entity = $this->activityRepository->find($id); if (null === $entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); @@ -361,8 +390,8 @@ final class ActivityController extends AbstractController ])->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $em->persist($entity); - $em->flush(); + $this->entityManager->persist($entity); + $this->entityManager->flush(); $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); @@ -406,7 +435,6 @@ final class ActivityController extends AbstractController public function deleteAction(Request $request, $id) { $view = null; - $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); @@ -416,8 +444,7 @@ final class ActivityController extends AbstractController $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; } - /* @var Activity $activity */ - $activity = $em->getRepository(Activity::class)->find($id); + $activity = $this->activityRepository->find($id); if (!$activity) { throw $this->createNotFoundException('Unable to find Activity entity.'); @@ -449,8 +476,8 @@ final class ActivityController extends AbstractController 'attendee' => $activity->getAttendee() ]); - $em->remove($activity); - $em->flush(); + $this->entityManager->remove($activity); + $this->entityManager->flush(); $this->addFlash('success', $this->get('translator') ->trans("The activity has been successfully removed.")); @@ -490,12 +517,11 @@ final class ActivityController extends AbstractController private function getEntity(Request $request): array { - $em = $this->getDoctrine()->getManager(); $person = $accompanyingPeriod = null; if ($request->query->has('person_id')) { $person_id = $request->get('person_id'); - $person = $em->getRepository(Person::class)->find($person_id); + $person = $this->personRepository->find($person_id); if ($person === null) { throw $this->createNotFoundException('Person not found'); @@ -504,7 +530,7 @@ final class ActivityController extends AbstractController $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } elseif ($request->query->has('accompanying_period_id')) { $accompanying_period_id = $request->get('accompanying_period_id'); - $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id); + $accompanyingPeriod = $this->accompanyingPeriodRepository->find($accompanying_period_id); if ($accompanyingPeriod === null) { throw $this->createNotFoundException('Accompanying Period not found'); @@ -522,7 +548,8 @@ final class ActivityController extends AbstractController ]; } - private function buildParamsToUrl(?Person $person, ?AccompanyingPeriod $accompanyingPeriod): array { + private function buildParamsToUrl(?Person $person, ?AccompanyingPeriod $accompanyingPeriod): array + { $params = []; if (null !== $person) { diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php index a95424312..4b06ca9b5 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityTypeCategory.php @@ -1,31 +1,12 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Class ActivityTypeCateogry - * - * @package Chill\ActivityBundle\Entity * @ORM\Entity() * @ORM\Table(name="activitytypecategory") * @ORM\HasLifecycleCallbacks() @@ -37,7 +18,7 @@ class ActivityTypeCategory * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ - private ?int $id; + private ?int $id = null; /** * @ORM\Column(type="json") @@ -54,10 +35,7 @@ class ActivityTypeCategory */ private float $ordering = 0.0; - /** - * Get id - */ - public function getId(): int + public function getId(): ?int { return $this->id; } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php index 6614caace..3e5cab378 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php @@ -1,70 +1,39 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; +use Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository; +use Chill\ActivityBundle\Repository\ActivityReasonRepository; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\AggregatorInterface; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\Query\Expr\Join; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -/** - * - * - * @author Julien Fastré - */ -class ActivityReasonAggregator implements AggregatorInterface, - ExportElementValidatedInterface +class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface { - /** - * - * @var EntityRepository - */ - protected $categoryRepository; + protected ActivityReasonCategoryRepository $activityReasonCategoryRepository; - /** - * - * @var EntityRepository - */ - protected $reasonRepository; + protected ActivityReasonRepository $activityReasonRepository; - /** - * - * @var TranslatableStringHelper - */ - protected $stringHelper; + protected TranslatableStringHelperInterface $translatableStringHelper; public function __construct( - EntityRepository $categoryRepository, - EntityRepository $reasonRepository, - TranslatableStringHelper $stringHelper + ActivityReasonCategoryRepository $activityReasonCategoryRepository, + ActivityReasonRepository $activityReasonRepository, + TranslatableStringHelper $translatableStringHelper ) { - $this->categoryRepository = $categoryRepository; - $this->reasonRepository = $reasonRepository; - $this->stringHelper = $stringHelper; + $this->activityReasonCategoryRepository = $activityReasonCategoryRepository; + $this->activityReasonRepository = $activityReasonRepository; + $this->translatableStringHelper = $translatableStringHelper; } public function alterQuery(QueryBuilder $qb, $data) @@ -77,7 +46,7 @@ class ActivityReasonAggregator implements AggregatorInterface, $elem = 'category.id'; $alias = 'activity_categories_id'; } else { - throw new \RuntimeException('the data provided are not recognized'); + throw new \RuntimeException('The data provided are not recognized.'); } $qb->addSelect($elem.' as '.$alias); @@ -93,11 +62,12 @@ class ActivityReasonAggregator implements AggregatorInterface, (! array_key_exists('activity', $join)) ) { $qb->add( - 'join', - array('activity' => - new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') - ), - true); + 'join', + [ + 'activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') + ], + true + ); } // join category if necessary @@ -143,28 +113,33 @@ class ActivityReasonAggregator implements AggregatorInterface, public function buildForm(FormBuilderInterface $builder) { - $builder->add('level', ChoiceType::class, array( - 'choices' => array( - 'By reason' => 'reasons', - 'By category of reason' => 'categories' - ), - 'multiple' => false, - 'expanded' => true, - 'label' => 'Reason\'s level' - )); + $builder->add( + 'level', + ChoiceType::class, + [ + 'choices' => [ + 'By reason' => 'reasons', + 'By category of reason' => 'categories' + ], + 'multiple' => false, + 'expanded' => true, + 'label' => "Reason's level" + ] + ); } public function validateForm($data, ExecutionContextInterface $context) { if ($data['level'] === null) { - $context->buildViolation("The reasons's level should not be empty") + $context + ->buildViolation("The reasons's level should not be empty.") ->addViolation(); } } - public function getTitle() + public function getTitle() { - return "Aggregate by activity reason"; + return 'Aggregate by activity reason'; } public function addRole() @@ -177,41 +152,33 @@ class ActivityReasonAggregator implements AggregatorInterface, // for performance reason, we load data from db only once switch ($data['level']) { case 'reasons': - $this->reasonRepository->findBy(array('id' => $values)); + $this->activityReasonRepository->findBy(['id' => $values]); break; case 'categories': - $this->categoryRepository->findBy(array('id' => $values)); + $this->activityReasonCategoryRepository->findBy(['id' => $values]); break; default: - throw new \RuntimeException(sprintf("the level data '%s' is invalid", - $data['level'])); + throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level'])); } return function($value) use ($data) { if ($value === '_header') { - return $data['level'] === 'reasons' ? - 'Group by reasons' - : - 'Group by categories of reason' - ; + return $data['level'] === 'reasons' ? 'Group by reasons' : 'Group by categories of reason'; } switch ($data['level']) { case 'reasons': - /* @var $r \Chill\ActivityBundle\Entity\ActivityReason */ - $r = $this->reasonRepository->find($value); + $r = $this->activityReasonRepository->find($value); - return $this->stringHelper->localize($r->getCategory()->getName()) - ." > " - . $this->stringHelper->localize($r->getName()); - ; - break; + return sprintf( + "%s > %s", + $this->translatableStringHelper->localize($r->getCategory()->getName()), + $this->translatableStringHelper->localize($r->getName()) + ); case 'categories': - $c = $this->categoryRepository->find($value); + $c = $this->activityReasonCategoryRepository->find($value); - return $this->stringHelper->localize($c->getName()); - break; - // no need for a default : the default was already set above + return $this->translatableStringHelper->localize($c->getName()); } }; @@ -222,12 +189,14 @@ class ActivityReasonAggregator implements AggregatorInterface, // add select element if ($data['level'] === 'reasons') { return array('activity_reasons_id'); - } elseif ($data['level'] === 'categories') { - return array ('activity_categories_id'); - } else { - throw new \RuntimeException('the data provided are not recognised'); } + if ($data['level'] === 'categories') { + return array ('activity_categories_id'); + } + + throw new \RuntimeException('The data provided are not recognised.'); + } } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php index a0e6d3966..bd90e8eb6 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php @@ -1,61 +1,32 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Aggregator; +use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\AggregatorInterface; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\Query\Expr\Join; -/** - * - * - * @author Julien Fastré - */ class ActivityTypeAggregator implements AggregatorInterface { + protected ActivityTypeRepository $activityTypeRepository; - /** - * - * @var EntityRepository - */ - protected $typeRepository; + protected TranslatableStringHelperInterface $translatableStringHelper; - /** - * - * @var TranslatableStringHelper - */ - protected $stringHelper; - - const KEY = 'activity_type_aggregator'; + public const KEY = 'activity_type_aggregator'; public function __construct( - EntityRepository $typeRepository, - TranslatableStringHelper $stringHelper + ActivityTypeRepository $activityTypeRepository, + TranslatableStringHelperInterface $translatableStringHelper ) { - $this->typeRepository = $typeRepository; - $this->stringHelper = $stringHelper; + $this->activityTypeRepository = $activityTypeRepository; + $this->translatableStringHelper = $translatableStringHelper; } public function alterQuery(QueryBuilder $qb, $data) @@ -64,7 +35,7 @@ class ActivityTypeAggregator implements AggregatorInterface $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); // add the "group by" part - $groupBy = $qb->addGroupBy(self::KEY); + $qb->addGroupBy(self::KEY); } /** @@ -97,7 +68,7 @@ class ActivityTypeAggregator implements AggregatorInterface public function getTitle() { - return "Aggregate by activity type"; + return 'Aggregate by activity type'; } public function addRole() @@ -108,17 +79,16 @@ class ActivityTypeAggregator implements AggregatorInterface public function getLabels($key, array $values, $data): \Closure { // for performance reason, we load data from db only once - $this->typeRepository->findBy(array('id' => $values)); + $this->activityTypeRepository->findBy(['id' => $values]); return function($value): string { if ($value === '_header') { return 'Activity type'; } - /* @var $r \Chill\ActivityBundle\Entity\ActivityType */ - $t = $this->typeRepository->find($value); + $t = $this->activityTypeRepository->find($value); - return $this->stringHelper->localize($t->getName()); + return $this->translatableStringHelper->localize($t->getName()); }; } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php index ca01e0ae5..8e4635ef2 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php @@ -1,51 +1,26 @@ - * - * 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 . - */ + namespace Chill\ActivityBundle\Export\Aggregator; +use Chill\MainBundle\Repository\UserRepository; use Symfony\Component\Form\FormBuilderInterface; use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Export\AggregatorInterface; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Query\Expr\Join; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityManagerInterface; -use Chill\MainBundle\Entity\User; -/** - * - * - * @author Julien Fastré - */ class ActivityUserAggregator implements AggregatorInterface { - /** - * - * @var EntityManagerInterface - */ - protected $em; - - const KEY = 'activity_user_id'; - - function __construct(EntityManagerInterface $em) - { - $this->em = $em; + public const KEY = 'activity_user_id'; + + private UserRepository $userRepository; + + public function __construct( + UserRepository $userRepository + ) { + $this->userRepository = $userRepository; } - + public function addRole() { return new Role(ActivityStatsVoter::STATS); @@ -53,9 +28,9 @@ class ActivityUserAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - // add select element + // add select element $qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY)); - + // add the "group by" part $qb->addGroupBy(self::KEY); } @@ -73,17 +48,14 @@ class ActivityUserAggregator implements AggregatorInterface public function getLabels($key, $values, $data): \Closure { // preload users at once - $this->em->getRepository(User::class) - ->findBy(['id' => $values]); - + $this->userRepository->findBy(['id' => $values]); + return function($value) { - switch ($value) { - case '_header': - return 'activity user'; - default: - return $this->em->getRepository(User::class)->find($value) - ->getUsername(); + if ($value === '_header') { + return 'activity user'; } + + return $this->userRepository->find($value)->getUsername(); }; } @@ -94,6 +66,6 @@ class ActivityUserAggregator implements AggregatorInterface public function getTitle(): string { - return "Aggregate by activity user"; + return 'Aggregate by activity user'; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php index 3498d7a13..3d5d798f8 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php @@ -1,64 +1,40 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Export; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Export\ExportInterface; -use Doctrine\ORM\QueryBuilder; +use Chill\MainBundle\Export\FormatterInterface; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Security\Core\Role\Role; use Doctrine\ORM\Query; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityManagerInterface; -/** - * - * - * @author Julien Fastré - */ class CountActivity implements ExportInterface { - /** - * - * @var EntityManagerInterface - */ - protected $entityManager; - + protected ActivityRepository $activityRepository; + public function __construct( - EntityManagerInterface $em - ) - { - $this->entityManager = $em; + ActivityRepository $activityRepository + ) { + $this->activityRepository = $activityRepository; } - - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) + + public function buildForm(FormBuilderInterface $builder) { - + } public function getDescription() { - return "Count activities by various parameters."; + return 'Count activities by various parameters.'; } public function getTitle() { - return "Count activities"; + return 'Count activities'; } public function getType() @@ -68,26 +44,26 @@ class CountActivity implements ExportInterface public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) { - $qb = $this->entityManager->createQueryBuilder(); - $centers = array_map(function($el) { return $el['center']; }, $acl); - - $qb->select('COUNT(activity.id) as export_count_activity') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ; - - $qb->where($qb->expr()->in('person.center', ':centers')) - ->setParameter('centers', $centers) - ; - + $centers = array_map(static fn($el) => $el['center'], $acl); + + $qb = $this + ->activityRepository + ->createQueryBuilder('activity') + ->select('COUNT(activity.id) as export_count_activity') + ->join('activity.person', 'person'); + + $qb + ->where($qb->expr()->in('person.center', ':centers')) + ->setParameter('centers', $centers); + return $qb; } - + public function supportsModifiers() { - return array('person', 'activity'); + return ['person', 'activity']; } - + public function requiredRole() { return new Role(ActivityStatsVoter::STATS); @@ -95,7 +71,7 @@ class CountActivity implements ExportInterface public function getAllowedFormattersTypes() { - return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); + return [FormatterInterface::TYPE_TABULAR]; } public function getLabels($key, array $values, $data) @@ -103,19 +79,13 @@ class CountActivity implements ExportInterface if ($key !== 'export_count_activity') { throw new \LogicException("the key $key is not used by this export"); } - - return function($value) { - return $value === '_header' ? - 'Number of activities' - : - $value - ; - }; + + return static fn($value) => $value === '_header' ? 'Number of activities' : $value; } public function getQueryKeys($data) { - return array('export_count_activity'); + return ['export_count_activity']; } public function getResult($qb, $data) diff --git a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php index 6e5d7b0b8..12338e225 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php @@ -1,31 +1,14 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Export; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Export\ListInterface; use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Scope; -use Chill\ActivityBundle\Entity\ActivityType; -use Doctrine\ORM\Query\Expr; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Doctrine\DBAL\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Symfony\Component\Form\FormBuilderInterface; @@ -37,33 +20,17 @@ use Chill\MainBundle\Export\FormatterInterface; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * Create a list for all activities - * - * @author Julien Fastré - */ class ListActivity implements ListInterface { + private ActivityRepository $activityRepository; - /** - * - * @var EntityManagerInterface - */ - protected $entityManager; + protected EntityManagerInterface $entityManager; - /** - * - * @var TranslatorInterface - */ - protected $translator; + protected TranslatorInterface $translator; - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + protected TranslatableStringHelperInterface $translatableStringHelper; - protected $fields = array( + protected array $fields = [ 'id', 'date', 'durationTime', @@ -75,32 +42,28 @@ class ListActivity implements ListInterface 'person_firstname', 'person_lastname', 'person_id' - ); + ]; public function __construct( - EntityManagerInterface $em, - TranslatorInterface $translator, - TranslatableStringHelper $translatableStringHelper - ) - { + EntityManagerInterface $em, + TranslatorInterface $translator, + TranslatableStringHelperInterface $translatableStringHelper, + ActivityRepository $activityRepository + ) { $this->entityManager = $em; $this->translator = $translator; $this->translatableStringHelper = $translatableStringHelper; + $this->activityRepository = $activityRepository; } - /** - * {@inheritDoc} - * - * @param FormBuilderInterface $builder - */ public function buildForm(FormBuilderInterface $builder) { - $builder->add('fields', ChoiceType::class, array( + $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, 'choices' => array_combine($this->fields, $this->fields), 'label' => 'Fields to include in export', - 'constraints' => [new Callback(array( + 'constraints' => [new Callback([ 'callback' => function($selected, ExecutionContextInterface $context) { if (count($selected) === 0) { $context->buildViolation('You must select at least one element') @@ -108,19 +71,14 @@ class ListActivity implements ListInterface ->addViolation(); } } - ))] - )); + ])] + ]); } - /** - * {@inheritDoc} - * - * @return type - */ public function getAllowedFormattersTypes() { - return array(FormatterInterface::TYPE_LIST); + return [FormatterInterface::TYPE_LIST]; } public function getDescription() @@ -133,29 +91,32 @@ class ListActivity implements ListInterface switch ($key) { case 'date' : - return function($value) { - if ($value === '_header') return 'date'; + return static function($value) { + if ($value === '_header') { + return 'date'; + } $date = \DateTime::createFromFormat('Y-m-d H:i:s', $value); return $date->format('d-m-Y'); }; case 'attendee': - return function($value) { - if ($value === '_header') return 'attendee'; + return static function($value) { + if ($value === '_header') { + return 'attendee'; + } return $value ? 1 : 0; }; case 'list_reasons' : - /* @var $activityReasonsRepository EntityRepository */ - $activityRepository = $this->entityManager - ->getRepository('ChillActivityBundle:Activity'); + $activityRepository = $this->activityRepository; - return function($value) use ($activityRepository) { - if ($value === '_header') return 'activity reasons'; + return function($value) use ($activityRepository): string { + if ($value === '_header') { + return 'activity reasons'; + } - $activity = $activityRepository - ->find($value); + $activity = $activityRepository->find($value); return implode(", ", array_map(function(ActivityReason $r) { @@ -168,21 +129,25 @@ class ListActivity implements ListInterface }; case 'circle_name' : return function($value) { - if ($value === '_header') return 'circle'; + if ($value === '_header') { + return 'circle'; + } - return $this->translatableStringHelper - ->localize(json_decode($value, true)); + return $this->translatableStringHelper->localize(json_decode($value, true)); }; case 'type_name' : return function($value) { - if ($value === '_header') return 'activity type'; + if ($value === '_header') { + return 'activity type'; + } - return $this->translatableStringHelper - ->localize(json_decode($value, true)); + return $this->translatableStringHelper->localize(json_decode($value, true)); }; default: - return function($value) use ($key) { - if ($value === '_header') return $key; + return static function($value) use ($key) { + if ($value === '_header') { + return $key; + } return $value; }; @@ -209,14 +174,13 @@ class ListActivity implements ListInterface return 'activity'; } - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { $centers = array_map(function($el) { return $el['center']; }, $acl); // throw an error if any fields are present if (!\array_key_exists('fields', $data)) { - throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " - . "have been checked"); + throw new InvalidArgumentException('Any fields have been checked.'); } $qb = $this->entityManager->createQueryBuilder(); @@ -227,7 +191,6 @@ class ListActivity implements ListInterface ->join('person.center', 'center') ->andWhere('center IN (:authorized_centers)') ->setParameter('authorized_centers', $centers); - ; foreach ($this->fields as $f) { if (in_array($f, $data['fields'])) { @@ -269,8 +232,6 @@ class ListActivity implements ListInterface } } - - return $qb; } @@ -281,7 +242,7 @@ class ListActivity implements ListInterface public function supportsModifiers() { - return array('activity', 'person'); + return ['activity', 'person']; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php index 0d48130b6..f22623d9f 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php @@ -4,12 +4,13 @@ declare(strict_types=1); namespace Chill\ActivityBundle\Export\Export; +use Chill\ActivityBundle\Repository\ActivityRepository; use Chill\MainBundle\Export\ExportInterface; -use Doctrine\ORM\QueryBuilder; +use Chill\MainBundle\Export\FormatterInterface; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Security\Core\Role\Role; use Doctrine\ORM\Query; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityManagerInterface; /** * This export allow to compute stats on activity duration. @@ -18,7 +19,7 @@ use Doctrine\ORM\EntityManagerInterface; */ class StatActivityDuration implements ExportInterface { - protected EntityManagerInterface $entityManager; + private ActivityRepository $activityRepository; public const SUM = 'sum'; @@ -30,13 +31,15 @@ class StatActivityDuration implements ExportInterface /** * @param string $action the stat to perform */ - public function __construct(EntityManagerInterface $em, string $action = 'sum') - { - $this->entityManager = $em; + public function __construct( + ActivityRepository $activityRepository, + string $action = 'sum' + ) { $this->action = $action; + $this->activityRepository = $activityRepository; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder) { } @@ -68,7 +71,7 @@ class StatActivityDuration implements ExportInterface $acl ); - $qb = $this->entityManager->createQueryBuilder(); + $qb = $this->activityRepository->createQueryBuilder('activity'); $select = null; @@ -77,7 +80,6 @@ class StatActivityDuration implements ExportInterface } return $qb->select($select) - ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.person', 'person') ->join('person.center', 'center') ->where($qb->expr()->in('center', ':centers')) @@ -96,7 +98,7 @@ class StatActivityDuration implements ExportInterface public function getAllowedFormattersTypes() { - return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); + return [FormatterInterface::TYPE_TABULAR]; } public function getLabels($key, array $values, $data) diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php index dca4cec30..2e0149a38 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -1,25 +1,12 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\Extension\Core\Type\DateType; @@ -28,34 +15,24 @@ use Chill\MainBundle\Form\Type\Export\FilterType; use Doctrine\ORM\Query\Expr; use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class ActivityDateFilter implements FilterInterface { - /** - * - * @var TranslatorInterface - */ - protected $translator; - + protected TranslatorInterface $translator; + function __construct(TranslatorInterface $translator) { $this->translator = $translator; } - public function addRole() { return null; } - public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->between('activity.date', ':date_from', + $clause = $qb->expr()->between('activity.date', ':date_from', ':date_to'); if ($where instanceof Expr\Andx) { @@ -63,7 +40,7 @@ class ActivityDateFilter implements FilterInterface } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('date_from', $data['date_from']); $qb->setParameter('date_to', $data['date_to']); @@ -74,35 +51,43 @@ class ActivityDateFilter implements FilterInterface return 'activity'; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Activities after this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', - 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Activities before this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', - 'format' => 'dd-MM-yyyy', - )); - + $builder->add( + 'date_from', + DateType::class, + [ + 'label' => 'Activities after this date', + 'data' => new \DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget'=> 'single_text', + 'format' => 'dd-MM-yyyy', + ] + ); + + $builder->add( + 'date_to', + DateType::class, + [ + 'label' => 'Activities before this date', + 'data' => new \DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget'=> 'single_text', + 'format' => 'dd-MM-yyyy', + ] + ); + $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { /* @var $filterForm \Symfony\Component\Form\FormInterface */ $filterForm = $event->getForm()->getParent(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); - + if ($enabled === true) { // if the filter is enabled, add some validation $form = $event->getForm(); $date_from = $form->get('date_from')->getData(); $date_to = $form->get('date_to')->getData(); - + // check that fields are not empty if ($date_from === null) { $form->get('date_from')->addError(new FormError( @@ -113,8 +98,8 @@ class ActivityDateFilter implements FilterInterface $form->get('date_to')->addError(new FormError( $this->translator->trans('This field ' . 'should not be empty'))); - } - + } + // check that date_from is before date_to if ( ($date_from !== null && $date_to !== null) @@ -132,17 +117,18 @@ class ActivityDateFilter implements FilterInterface public function describeAction($data, $format = 'string') { - return array( - "Filtered by date of activity: only between %date_from% and %date_to%", - array( - "%date_from%" => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y') - )); + return [ + 'Filtered by date of activity: only between %date_from% and %date_to%', + [ + '%date_from%' => $data['date_from']->format('d-m-Y'), + '%date_to%' => $data['date_to']->format('d-m-Y') + ] + ]; } public function getTitle() { - return "Filtered by date activity"; + return 'Filtered by date activity'; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php index 37157af60..dbdceaaab 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php @@ -1,25 +1,12 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Filter; +use Chill\ActivityBundle\Repository\ActivityReasonRepository; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; @@ -28,41 +15,24 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\Query\Expr; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\Expr\Join; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; -/** - * - * - * @author Julien Fastré - */ -class ActivityReasonFilter implements FilterInterface, - ExportElementValidatedInterface +class ActivityReasonFilter implements FilterInterface, ExportElementValidatedInterface { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * The repository for activity reasons - * - * @var EntityRepository - */ - protected $reasonRepository; - + protected TranslatableStringHelperInterface $translatableStringHelper; + + protected ActivityReasonRepository $activityReasonRepository; + public function __construct( - TranslatableStringHelper $helper, - EntityRepository $reasonRepository + TranslatableStringHelper $helper, + ActivityReasonRepository $activityReasonRepository ) { $this->translatableStringHelper = $helper; - $this->reasonRepository = $reasonRepository; + $this->activityReasonRepository = $activityReasonRepository; } - - + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); @@ -75,12 +45,12 @@ class ActivityReasonFilter implements FilterInterface, && !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') ) - OR + || (! array_key_exists('activity', $join)) ) { $qb->add( - 'join', - array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')), + 'join', + array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')), true ); } @@ -90,25 +60,25 @@ class ActivityReasonFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('selected_activity_reasons', $data['reasons']); } - + /** * Check if a join between Activity and Reason is already defined - * + * * @param Join[] $joins * @return boolean */ - private function checkJoinAlreadyDefined(array $joins, $alias) + private function checkJoinAlreadyDefined(array $joins, $alias): bool { foreach ($joins as $join) { if ($join->getAlias() === $alias) { return true; } } - + return false; } @@ -119,51 +89,47 @@ class ActivityReasonFilter implements FilterInterface, public function buildForm(FormBuilderInterface $builder) { - //create a local copy of translatableStringHelper - $helper = $this->translatableStringHelper; - - $builder->add('reasons', EntityType::class, array( - 'class' => 'ChillActivityBundle:ActivityReason', - 'choice_label' => function (ActivityReason $reason) use ($helper) { - return $helper->localize($reason->getName()); - }, - 'group_by' => function(ActivityReason $reason) use ($helper) { - return $helper->localize($reason->getCategory()->getName()); - }, + $builder->add('reasons', EntityType::class, [ + 'class' => ActivityReason::class, + 'choice_label' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()), + 'group_by' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()), 'multiple' => true, 'expanded' => false - )); + ]); } - + public function validateForm($data, ExecutionContextInterface $context) { if ($data['reasons'] === null || count($data['reasons']) === 0) { - $context->buildViolation("At least one reason must be choosen") + $context + ->buildViolation('At least one reason must be chosen') ->addViolation(); } } - public function getTitle() + public function getTitle() { return 'Filter by reason'; } - + public function addRole() { return new Role(ActivityStatsVoter::STATS); } - + public function describeAction($data, $format = 'string') { // collect all the reasons'name used in this filter in one array $reasonsNames = array_map( - function(ActivityReason $r) { - return "\"".$this->translatableStringHelper->localize($r->getName())."\""; - }, - $this->reasonRepository->findBy(array('id' => $data['reasons']->toArray())) - ); - - return array("Filtered by reasons: only %list%", - ["%list%" => implode(", ", $reasonsNames)]); + fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', + $this->activityReasonRepository->findBy(array('id' => $data['reasons']->toArray())) + ); + + return [ + 'Filtered by reasons: only %list%', + [ + '%list%' => implode(", ", $reasonsNames), + ] + ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php index b3616da10..7bf1e7210 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php @@ -1,67 +1,37 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Filter; +use Chill\ActivityBundle\Repository\ActivityTypeRepository; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\Query\Expr; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\Expr\Join; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\ActivityBundle\Entity\ActivityType; -/** - * - * - */ -class ActivityTypeFilter implements FilterInterface, - ExportElementValidatedInterface +class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInterface { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * The repository for activity reasons - * - * @var EntityRepository - */ - protected $typeRepository; - + protected TranslatableStringHelperInterface $translatableStringHelper; + + protected ActivityTypeRepository $activityTypeRepository; + public function __construct( - TranslatableStringHelper $helper, - EntityRepository $typeRepository + TranslatableStringHelperInterface $translatableStringHelper, + ActivityTypeRepository $activityTypeRepository ) { - $this->translatableStringHelper = $helper; - $this->typeRepository = $typeRepository; + $this->translatableStringHelper = $translatableStringHelper; + $this->activityTypeRepository = $activityTypeRepository; } - - + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); @@ -72,14 +42,14 @@ class ActivityTypeFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('selected_activity_types', $data['types']); } - + /** * Check if a join between Activity and Reason is already defined - * + * * @param Join[] $joins * @return boolean */ @@ -90,7 +60,7 @@ class ActivityTypeFilter implements FilterInterface, return true; } } - + return false; } @@ -101,48 +71,50 @@ class ActivityTypeFilter implements FilterInterface, public function buildForm(FormBuilderInterface $builder) { - //create a local copy of translatableStringHelper - $helper = $this->translatableStringHelper; - - $builder->add('types', EntityType::class, array( - 'class' => ActivityType::class, - 'choice_label' => function (ActivityType $type) use ($helper) { - return $helper->localize($type->getName()); - }, - 'multiple' => true, - 'expanded' => false - )); + $builder->add( + 'types', + EntityType::class, + [ + 'class' => ActivityType::class, + 'choice_label' => fn(ActivityType $type) => $this->translatableStringHelper->localize($type->getName()), + 'multiple' => true, + 'expanded' => false + ] + ); } - + public function validateForm($data, ExecutionContextInterface $context) { if ($data['types'] === null || count($data['types']) === 0) { - $context->buildViolation("At least one type must be choosen") + $context + ->buildViolation('At least one type must be chosen') ->addViolation(); } } - public function getTitle() + public function getTitle() { return 'Filter by activity type'; } - + public function addRole() { return new Role(ActivityStatsVoter::STATS); } - + public function describeAction($data, $format = 'string') { // collect all the reasons'name used in this filter in one array $reasonsNames = array_map( - function(ActivityType $t) { - return "\"".$this->translatableStringHelper->localize($t->getName())."\""; - }, - $this->typeRepository->findBy(array('id' => $data['types']->toArray())) - ); - - return array("Filtered by activity type: only %list%", - ["%list%" => implode(", ", $reasonsNames)]); + fn(ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"', + $this->activityTypeRepository->findBy(['id' => $data['types']->toArray()]) + ); + + return [ + 'Filtered by activity type: only %list%', + [ + '%list%' => implode(", ", $reasonsNames), + ] + ]; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php index cf444bd0a..d150c68e6 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php @@ -1,25 +1,14 @@ - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Export\Filter; +use Chill\ActivityBundle\Repository\ActivityReasonRepository; use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\Extension\Core\Type\DateType; @@ -29,78 +18,58 @@ use Doctrine\ORM\Query\Expr; use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Chill\ActivityBundle\Entity\ActivityReason; -use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\EntityManager; use Chill\PersonBundle\Export\Declarations; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; -/** - * - * - * @author Julien Fastré - */ -class PersonHavingActivityBetweenDateFilter implements FilterInterface, - ExportElementValidatedInterface +class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportElementValidatedInterface { - - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * - * @var EntityRepository - */ - protected $activityReasonRepository; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - + protected TranslatableStringHelperInterface $translatableStringHelper; + + protected ActivityReasonRepository $activityReasonRepository; + + protected TranslatorInterface $translator; + public function __construct( - TranslatableStringHelper $translatableStringHelper, - EntityRepository $activityReasonRepository, - TranslatorInterface $translator + TranslatableStringHelper $translatableStringHelper, + ActivityReasonRepository $activityReasonRepository, + TranslatorInterface $translator ) { $this->translatableStringHelper = $translatableStringHelper; $this->activityReasonRepository = $activityReasonRepository; - $this->translator = $translator; + $this->translator = $translator; } - public function addRole() { return null; } - public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) + public function alterQuery(QueryBuilder $qb, $data) { // create a query for activity $sqb = $qb->getEntityManager()->createQueryBuilder(); - $sqb->select("person_person_having_activity.id") - ->from("ChillActivityBundle:Activity", "activity_person_having_activity") - ->join("activity_person_having_activity.person", "person_person_having_activity") - ; + $sqb->select('person_person_having_activity.id') + ->from('ChillActivityBundle:Activity', 'activity_person_having_activity') + ->join('activity_person_having_activity.person', 'person_person_having_activity'); + // add clause between date - $sqb->where("activity_person_having_activity.date BETWEEN " - . ":person_having_activity_between_date_from" - . " AND " - . ":person_having_activity_between_date_to"); + $sqb->where('activity_person_having_activity.date BETWEEN ' + . ':person_having_activity_between_date_from' + . ' AND ' + . ':person_having_activity_between_date_to'); + // add clause activity reason - $sqb->join('activity_person_having_activity.reasons', - 'reasons_person_having_activity'); + $sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity'); + $sqb->andWhere( - $sqb->expr()->in( - 'reasons_person_having_activity', - ":person_having_activity_reasons") - ); - + $sqb->expr()->in( + 'reasons_person_having_activity', ':person_having_activity_reasons' + ) + ); + $where = $qb->getDQLPart('where'); $clause = $qb->expr()->in('person.id', $sqb->getDQL()); @@ -109,11 +78,11 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); - $qb->setParameter('person_having_activity_between_date_from', + $qb->setParameter('person_having_activity_between_date_from', $data['date_from']); - $qb->setParameter('person_having_activity_between_date_to', + $qb->setParameter('person_having_activity_between_date_to', $data['date_to']); $qb->setParameter('person_having_activity_reasons', $data['reasons']); } @@ -123,51 +92,45 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, return Declarations::PERSON_IMPLIED_IN; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) + public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Implied in an activity after this date", + $builder->add('date_from', DateType::class, [ + 'label' => 'Implied in an activity after this date', 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), + 'attr' => ['class' => 'datepicker'], 'widget'=> 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Implied in an activity before this date", + ]); + + $builder->add('date_to', DateType::class, [ + 'label' => 'Implied in an activity before this date', 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), + 'attr' => ['class' => 'datepicker'], 'widget'=> 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('reasons', EntityType::class, array( - 'class' => 'ChillActivityBundle:ActivityReason', - 'choice_label' => function (ActivityReason $reason) { - return $this->translatableStringHelper - ->localize($reason->getName()); - }, - 'group_by' => function(ActivityReason $reason) { - return $this->translatableStringHelper - ->localize($reason->getCategory()->getName()); - }, + ]); + + $builder->add('reasons', EntityType::class, [ + 'class' => ActivityReason::class, + 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()), + 'group_by' => fn(ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()), 'data' => $this->activityReasonRepository->findAll(), 'multiple' => true, 'expanded' => false, - 'label' => "Activity reasons for those activities" - )); - + 'label' => 'Activity reasons for those activities' + ]); + $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { - /* @var $filterForm \Symfony\Component\Form\FormInterface */ + /* @var FormInterface $filterForm */ $filterForm = $event->getForm()->getParent(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); - + if ($enabled === true) { // if the filter is enabled, add some validation $form = $event->getForm(); $date_from = $form->get('date_from')->getData(); $date_to = $form->get('date_to')->getData(); - + // check that fields are not empty if ($date_from === null) { $form->get('date_from')->addError(new FormError( @@ -178,8 +141,8 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, $form->get('date_to')->addError(new FormError( $this->translator->trans('This field ' . 'should not be empty'))); - } - + } + // check that date_from is before date_to if ( ($date_from !== null && $date_to !== null) @@ -194,35 +157,37 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, } }); } - + public function validateForm($data, ExecutionContextInterface $context) { if ($data['reasons'] === null || count($data['reasons']) === 0) { - $context->buildViolation("At least one reason must be choosen") + $context->buildViolation('At least one reason must be chosen') ->addViolation(); } } public function describeAction($data, $format = 'string') { - return array( - "Filtered by person having an activity between %date_from% and " - . "%date_to% with reasons %reasons_name%", - array( - "%date_from%" => $data['date_from']->format('d-m-Y'), + return [ + 'Filtered by person having an activity between %date_from% and ' + . '%date_to% with reasons %reasons_name%', + [ + '%date_from%' => $data['date_from']->format('d-m-Y'), '%date_to%' => $data['date_to']->format('d-m-Y'), - "%reasons_name%" => implode(", ", array_map( - function (ActivityReason $r) { - return '"'.$this->translatableStringHelper-> - localize($r->getName()).'"'; - }, - $data['reasons'])) - )); + '%reasons_name%' => implode( + ", ", + array_map( + fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"', + $data['reasons'] + ) + ) + ] + ]; } public function getTitle() { - return "Filtered by person having an activity in a period"; + return 'Filtered by person having an activity in a period'; } } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php index fa4b23212..f930d3c1a 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php @@ -1,56 +1,29 @@ , - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Form\Type; +use Chill\ActivityBundle\Repository\ActivityTypeRepository; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\EntityRepository; use Chill\ActivityBundle\Entity\ActivityType; -/** - * Description of TranslatableActivityType - * - * @author Champs-Libres Coop - */ class TranslatableActivityType extends AbstractType { + protected TranslatableStringHelperInterface $translatableStringHelper; - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - protected $activityTypeRepository; + protected ActivityTypeRepository $activityTypeRepository; public function __construct( - TranslatableStringHelper $helper, - EntityRepository $activityTypeRepository - ) - { + TranslatableStringHelperInterface $helper, + ActivityTypeRepository $activityTypeRepository + ) { $this->translatableStringHelper = $helper; $this->activityTypeRepository = $activityTypeRepository; } @@ -65,22 +38,21 @@ class TranslatableActivityType extends AbstractType return EntityType::class; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) { - /* @var $qb \Doctrine\ORM\QueryBuilder */ + public function buildForm(FormBuilderInterface $builder, array $options) { + /* @var QueryBuilder $qb */ $qb = $options['query_builder']; if ($options['active_only'] === true) { $qb->where($qb->expr()->eq('at.active', ':active')); - $qb->setParameter('active', true, \Doctrine\DBAL\Types\Types::BOOLEAN); + $qb->setParameter('active', true, Types::BOOLEAN); } } public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults( array( - 'class' => 'ChillActivityBundle:ActivityType', + 'class' => ActivityType::class, 'active_only' => true, 'query_builder' => $this->activityTypeRepository ->createQueryBuilder('at'), diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityReasonCategoryRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityReasonCategoryRepository.php new file mode 100644 index 000000000..3026105b0 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityReasonCategoryRepository.php @@ -0,0 +1,23 @@ +, - * - * 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 . - */ +declare(strict_types=1); namespace Chill\ActivityBundle\Repository; @@ -29,10 +11,10 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; /** - * @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null) - * @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null) - * @method AccompanyingPeriodParticipation[] findAll() - * @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * @method Activity|null find($id, $lockMode = null, $lockVersion = null) + * @method Activity|null findOneBy(array $criteria, array $orderBy = null) + * @method Activity[] findAll() + * @method Activity[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ class ActivityRepository extends ServiceEntityRepository { @@ -42,12 +24,7 @@ class ActivityRepository extends ServiceEntityRepository } /** - * @param $person - * @param array $scopes - * @param string[] $orderBy - * @param int $limit - * @param int $offset - * @return array|Activity[] + * @return Activity[] */ public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array { @@ -63,8 +40,7 @@ class ActivityRepository extends ServiceEntityRepository ':person MEMBER OF a.persons' ) ) - ->setParameter('person', $person) - ; + ->setParameter('person', $person); foreach ($orderBy as $k => $dir) { $qb->addOrderBy('a.'.$k, $dir); @@ -72,17 +48,11 @@ class ActivityRepository extends ServiceEntityRepository $qb->setMaxResults($limit)->setFirstResult($offset); - return $qb->getQuery() - ->getResult(); + return $qb->getQuery()->getResult(); } /** - * @param AccompanyingPeriod $period - * @param array $scopes - * @param int|null $limit - * @param int|null $offset - * @param array|string[] $orderBy - * @return array|Activity[] + * @return Activity[] */ public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array { @@ -92,8 +62,7 @@ class ActivityRepository extends ServiceEntityRepository if (!$allowNullScope) { $qb ->where($qb->expr()->in('a.scope', ':scopes')) - ->setParameter('scopes', $scopes) - ; + ->setParameter('scopes', $scopes); } else { $qb ->where( @@ -102,16 +71,14 @@ class ActivityRepository extends ServiceEntityRepository $qb->expr()->isNull('a.scope') ) ) - ->setParameter('scopes', $scopes) - ; + ->setParameter('scopes', $scopes); } $qb ->andWhere( $qb->expr()->eq('a.accompanyingPeriod', ':period') ) - ->setParameter('period', $period) - ; + ->setParameter('period', $period); foreach ($orderBy as $k => $dir) { $qb->addOrderBy('a.'.$k, $dir); @@ -119,7 +86,6 @@ class ActivityRepository extends ServiceEntityRepository $qb->setMaxResults($limit)->setFirstResult($offset); - return $qb->getQuery() - ->getResult(); + return $qb->getQuery()->getResult(); } } diff --git a/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php new file mode 100644 index 000000000..62a6a9a0d --- /dev/null +++ b/src/Bundle/ChillActivityBundle/Repository/ActivityTypeCategoryRepository.php @@ -0,0 +1,23 @@ +em->getClassMetadata(Activity::class); $associationMapping = $metadataActivity->getAssociationMapping('person'); $role = new Role('CHILL_ACTIVITY_SEE'); - $reachableScopes = $this->helper->getReachableScopes($this->user, - $role, $person->getCenter()); + $reachableScopes = $this->helper->getReachableScopes($this->user, $role->getRole(), $person->getCenter()); $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); $scopes_ids = []; diff --git a/src/Bundle/ChillActivityBundle/config/services.yaml b/src/Bundle/ChillActivityBundle/config/services.yaml index 0a65e08c8..4e93e38be 100644 --- a/src/Bundle/ChillActivityBundle/config/services.yaml +++ b/src/Bundle/ChillActivityBundle/config/services.yaml @@ -1,4 +1,7 @@ services: + _defaults: + autowire: true + autoconfigure: true chill.activity.timeline: class: Chill\ActivityBundle\Timeline\TimelineActivityProvider @@ -13,17 +16,14 @@ services: - { name: chill.timeline, context: 'center' } Chill\ActivityBundle\Menu\: - autowire: true - autoconfigure: true resource: '../Menu/' tags: ['chill.menu_builder'] Chill\ActivityBundle\Notification\: - autowire: true - autoconfigure: true resource: '../Notification' Chill\ActivityBundle\Security\Authorization\: resource: '../Security/Authorization/' - autowire: true - autoconfigure: true + + Chill\ActivityBundle\Repository\: + resource: '../Repository/' diff --git a/src/Bundle/ChillActivityBundle/config/services/export.yaml b/src/Bundle/ChillActivityBundle/config/services/export.yaml index 222e8b5e0..d8aa13098 100644 --- a/src/Bundle/ChillActivityBundle/config/services/export.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/export.yaml @@ -1,82 +1,56 @@ services: + _defaults: + autowire: true + autoconfigure: true + chill.activity.export.count_activity: class: Chill\ActivityBundle\Export\Export\CountActivity - arguments: - - "@doctrine.orm.entity_manager" tags: - { name: chill.export, alias: 'count_activity' } - + chill.activity.export.sum_activity_duration: class: Chill\ActivityBundle\Export\Export\StatActivityDuration - arguments: - - "@doctrine.orm.entity_manager" - - "sum" tags: - { name: chill.export, alias: 'sum_activity_duration' } - + chill.activity.export.list_activity: class: Chill\ActivityBundle\Export\Export\ListActivity - arguments: - - "@doctrine.orm.entity_manager" - - "@translator" - - "@chill.main.helper.translatable_string" tags: - { name: chill.export, alias: 'list_activity' } - + chill.activity.export.reason_filter: class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter - arguments: - - "@chill.main.helper.translatable_string" - - "@chill_activity.repository.reason" tags: - { name: chill.export_filter, alias: 'activity_reason_filter' } - + chill.activity.export.type_filter: class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter - arguments: - - "@chill.main.helper.translatable_string" - - "@chill_activity.repository.activity_type" tags: - { name: chill.export_filter, alias: 'activity_type_filter' } - + chill.activity.export.date_filter: class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter - arguments: - - "@translator" tags: - { name: chill.export_filter, alias: 'activity_date_filter' } chill.activity.export.person_having_an_activity_between_date_filter: class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter - arguments: - - "@chill.main.helper.translatable_string" - - "@chill_activity.repository.reason" - - "@translator" tags: - #0 register as a filter name: chill.export_filter alias: 'activity_person_having_ac_bw_date_filter' - + chill.activity.export.reason_aggregator: class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator - arguments: - - "@chill_activity.repository.reason_category" - - "@chill_activity.repository.reason" - - "@chill.main.helper.translatable_string" tags: - { name: chill.export_aggregator, alias: activity_reason_aggregator } - + chill.activity.export.type_aggregator: class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator - arguments: - - "@chill_activity.repository.activity_type" - - "@chill.main.helper.translatable_string" tags: - { name: chill.export_aggregator, alias: activity_type_aggregator } - + chill.activity.export.user_aggregator: class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator - arguments: - $em: "@doctrine.orm.entity_manager" tags: - { name: chill.export_aggregator, alias: activity_user_aggregator } diff --git a/src/Bundle/ChillActivityBundle/config/services/repositories.yaml b/src/Bundle/ChillActivityBundle/config/services/repositories.yaml index 26bc58ac9..c9fe8d843 100644 --- a/src/Bundle/ChillActivityBundle/config/services/repositories.yaml +++ b/src/Bundle/ChillActivityBundle/config/services/repositories.yaml @@ -1,28 +1,12 @@ --- services: - chill_activity.repository.activity_type: - class: Doctrine\ORM\EntityRepository - factory: ['@doctrine.orm.entity_manager', getRepository] - arguments: - - 'Chill\ActivityBundle\Entity\ActivityType' - - chill_activity.repository.reason: - class: Doctrine\ORM\EntityRepository - factory: ['@doctrine.orm.entity_manager', getRepository] - arguments: - - 'Chill\ActivityBundle\Entity\ActivityReason' - - chill_activity.repository.reason_category: - class: Doctrine\ORM\EntityRepository - factory: ['@doctrine.orm.entity_manager', getRepository] - arguments: - - 'Chill\ActivityBundle\Entity\ActivityReasonCategory' - - Chill\ActivityBundle\Repository\ActivityRepository: - tags: [doctrine.repository_service] - arguments: - - '@Doctrine\Persistence\ManagerRegistry' + chill_activity.repository.activity_type: '@Chill\ActivityBundle\Repository\ActivityTypeRepository' + chill_activity.repository.reason: '@Chill\ActivityBundle\Repository\ActivityReasonRepository' + chill_activity.repository.reason_category: '@Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository' + # This is not a repository but merely a service. It needs to be moved out for simplicity. + # The autowire and autoconfigure should be enabled globally and removed from the definition of the service. + # Once autoloaded, there is no need to alias it to the interface here, it will be done automatically by Symfony. Chill\ActivityBundle\Repository\ActivityACLAwareRepository: autowire: true autoconfigure: true diff --git a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php index 143e430f7..6c00274ad 100644 --- a/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php +++ b/src/Bundle/ChillAsideActivityBundle/src/Entity/AsideActivityCategory.php @@ -44,7 +44,7 @@ class AsideActivityCategory * @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children") * @ORM\JoinColumn(nullable=true) */ - private AsideActivityCategory $parent; + private ?AsideActivityCategory $parent = null; /** * @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent") diff --git a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php index da219abb9..6d0b9c7b6 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php @@ -1,42 +1,34 @@ configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -45,24 +37,23 @@ class ChargeType extends AbstractType 'placeholder' => 'Choose a charge type' ]) ->add('amount', MoneyType::class) - ->add('comment', TextAreaType::class, [ + ->add('comment', TextareaType::class, [ 'required' => false - ]) - ; - + ]); + if ($options['show_start_date']) { $builder->add('startDate', ChillDateType::class, [ 'label' => 'Start of validity period' ]); } - + if ($options['show_end_date']) { $builder->add('endDate', ChillDateType::class, [ 'required' => false, 'label' => 'End of validity period' ]); } - + if ($options['show_help']) { $builder->add('help', ChoiceType::class, [ 'choices' => [ @@ -77,48 +68,39 @@ class ChargeType extends AbstractType ]); } } - + private function getTypes() { $charges = $this->configRepository ->getChargesLabels(); - + // rewrite labels to filter in language foreach ($charges as $key => $labels) { $charges[$key] = $this->translatableStringHelper->localize($labels); } - + \asort($charges); - + return \array_flip($charges); } - - /** - * {@inheritdoc} - */ + public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( - 'data_class' => 'Chill\AMLI\BudgetBundle\Entity\Charge', + 'data_class' => Charge::class, 'show_start_date' => true, 'show_end_date' => true, 'show_help' => true )); - + $resolver ->setAllowedTypes('show_start_date', 'boolean') ->setAllowedTypes('show_end_date', 'boolean') - ->setAllowedTypes('show_help', 'boolean') - ; + ->setAllowedTypes('show_help', 'boolean'); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_amli_budgetbundle_charge'; } - - } diff --git a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php index abf7191ab..2df9ee6d7 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php @@ -1,7 +1,10 @@ configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder @@ -45,17 +38,16 @@ class ResourceType extends AbstractType 'label' => 'Resource element type' ]) ->add('amount', MoneyType::class) - ->add('comment', TextAreaType::class, [ + ->add('comment', TextareaType::class, [ 'required' => false - ]) - ; - + ]); + if ($options['show_start_date']) { $builder->add('startDate', ChillDateType::class, [ 'label' => 'Start of validity period' ]); } - + if ($options['show_end_date']) { $builder->add('endDate', ChillDateType::class, [ 'required' => false, @@ -63,25 +55,7 @@ class ResourceType extends AbstractType ]); } } - - private function getTypes() - { - $resources = $this->configRepository - ->getResourcesLabels(); - - // rewrite labels to filter in language - foreach ($resources as $key => $labels) { - $resources[$key] = $this->translatableStringHelper->localize($labels); - } - - asort($resources); - - return \array_flip($resources); - } - - /** - * {@inheritdoc} - */ + public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( @@ -89,20 +63,29 @@ class ResourceType extends AbstractType 'show_start_date' => true, 'show_end_date' => true )); - + $resolver ->setAllowedTypes('show_start_date', 'boolean') - ->setAllowedTypes('show_end_date', 'boolean') - ; + ->setAllowedTypes('show_end_date', 'boolean'); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_amli_budgetbundle_resource'; } + private function getTypes() + { + $resources = $this->configRepository + ->getResourcesLabels(); + // rewrite labels to filter in language + foreach ($resources as $key => $labels) { + $resources[$key] = $this->translatableStringHelper->localize($labels); + } + + asort($resources); + + return \array_flip($resources); + } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php b/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php index 3ee9d4dd5..1e25915ac 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php +++ b/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php @@ -1,38 +1,46 @@ em = $em; + $this->em = $entityManager; $this->translator = $translator; $this->chillMainLogger = $chillMainLogger; + $this->familyMemberRepository = $familyMemberRepository; } - /** * @Route( * "{_locale}/family-members/family-members/by-person/{id}", @@ -43,14 +51,12 @@ class FamilyMemberController extends Controller { $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person); - $familyMembers = $this->em - ->getRepository(FamilyMember::class) - ->findByPerson($person); + $familyMembers = $this->familyMemberRepository->findByPerson($person); - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', array( + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', [ 'person' => $person, 'familyMembers' => $familyMembers - )); + ]); } /** @@ -61,9 +67,7 @@ class FamilyMemberController extends Controller */ public function newAction(Person $person, Request $request) { - $familyMember = (new FamilyMember()) - ->setPerson($person) - ; + $familyMember = (new FamilyMember())->setPerson($person); $this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember); @@ -72,10 +76,9 @@ class FamilyMemberController extends Controller $form->handleRequest($request); - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($familyMember); - $em->flush(); + if ($form->isSubmitted() && $form->isValid()) { + $this->em->persist($familyMember); + $this->em->flush(); $this->addFlash('success', $this->translator->trans('Family member created')); @@ -84,10 +87,10 @@ class FamilyMemberController extends Controller ]); } - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', array( + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', [ 'form' => $form->createView(), 'person' => $person - )); + ]); } /** @@ -105,9 +108,8 @@ class FamilyMemberController extends Controller $form->handleRequest($request); - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->flush(); + if ($form->isSubmitted() && $form->isValid()) { + $this->em->flush(); $this->addFlash('success', $this->translator->trans('Family member updated')); @@ -116,11 +118,11 @@ class FamilyMemberController extends Controller ]); } - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', array( + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', [ 'familyMember' => $familyMember, 'form' => $form->createView(), 'person' => $familyMember->getPerson() - )); + ]); } /** @@ -129,47 +131,42 @@ class FamilyMemberController extends Controller * "{_locale}/family-members/family-members/{id}/delete", * name="chill_family_members_family_members_delete" * ) - * - * @param FamilyMember $familyMember - * @param Request $request - * @return \Symfony\Component\BrowserKit\Response */ - public function deleteAction(FamilyMember $familyMember, Request $request) + public function deleteAction(FamilyMember $familyMember, Request $request): Response { $this->denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not ' . 'allowed to delete this family membership'); - $form = $this->createDeleteForm($id); + $form = $this->createDeleteForm(); if ($request->getMethod() === Request::METHOD_DELETE) { $form->handleRequest($request); if ($form->isValid()) { - $this->chillMainLogger->notice("A family member has been removed", array( + $this->chillMainLogger->notice("A family member has been removed", [ 'by_user' => $this->getUser()->getUsername(), 'family_member_id' => $familyMember->getId(), 'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(), 'link' => $familyMember->getLink() - )); + ]); - $em = $this->getDoctrine()->getManager(); - $em->remove($familyMember); - $em->flush(); + $this->em->remove($familyMember); + $this->em->flush(); $this->addFlash('success', $this->translator ->trans("The family member has been successfully removed.")); - return $this->redirectToRoute('chill_family_members_family_members_index', array( + return $this->redirectToRoute('chill_family_members_family_members_index', [ 'id' => $familyMember->getPerson()->getId() - )); + ]); } } - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', array( + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', [ 'familyMember' => $familyMember, 'delete_form' => $form->createView() - )); + ]); } /** @@ -182,23 +179,20 @@ class FamilyMemberController extends Controller { $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember); - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', array( + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', [ 'familyMember' => $familyMember - )); + ]); } /** * Creates a form to delete a help request entity by id. - * - * @param mixed $id The entity id - * - * @return \Symfony\Component\Form\Form The form */ - private function createDeleteForm($id) + private function createDeleteForm(): FormInterface { - return $this->createFormBuilder() + return $this + ->createFormBuilder() ->setMethod(Request::METHOD_DELETE) - ->add('submit', SubmitType::class, array('label' => 'Delete')) + ->add('submit', SubmitType::class, ['label' => 'Delete']) ->getForm() ; } diff --git a/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php b/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php index 618128c96..a6754981b 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php +++ b/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php @@ -1,17 +1,32 @@ findBy([ 'person' => $person ]); + parent::__construct($registry, FamilyMember::class); + } + + /** + * @return FamilyMember[] + */ + public function findByPerson(Person $person): array + { + return $this->findBy(['person' => $person]); } } diff --git a/src/Bundle/ChillMainBundle/Entity/RoleScope.php b/src/Bundle/ChillMainBundle/Entity/RoleScope.php index 315e8f594..a92184917 100644 --- a/src/Bundle/ChillMainBundle/Entity/RoleScope.php +++ b/src/Bundle/ChillMainBundle/Entity/RoleScope.php @@ -1,5 +1,7 @@ new = true; $this->permissionsGroups = new ArrayCollection(); } - /** - * @return int - */ - public function getId() + public function getId(): ?int { return $this->id; } - /** - * @return string - */ - public function getRole() + public function getRole(): ?string { return $this->role; } - /** - * @return Scope - */ - public function getScope() + public function getScope(): ?Scope { return $this->scope; } - /** - * @param type $role - * @return RoleScope - */ - public function setRole($role) + public function setRole(?string $role = null): self { $this->role = $role; return $this; } - /** - * @param Scope $scope - * @return RoleScope - */ - public function setScope(Scope $scope = null) + public function setScope(?Scope $scope = null): self { $this->scope = $scope; diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php index 39af35706..f4dd9ba7c 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php @@ -1,48 +1,24 @@ - * - * 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 . - */ + +declare(strict_types=1); + namespace Chill\MainBundle\Security\Authorization; use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class ChillExportVoter extends Voter { - const EXPORT = 'chill_export'; - - /** - * - * @var AuthorizationHelper - */ - protected $authorizationHelper; - - public function __construct(AuthorizationHelper $authorizationHelper) + public const EXPORT = 'chill_export'; + + protected AuthorizationHelperInterface $authorizationHelper; + + public function __construct(AuthorizationHelperInterface $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } - + protected function supports($attribute, $subject): bool { return $attribute === self::EXPORT; @@ -53,10 +29,7 @@ class ChillExportVoter extends Voter if (!$token->getUser() instanceof User) { return false; } - - $centers = $this->authorizationHelper - ->getReachableCenters($token->getUser(), new Role($attribute)); - - return count($centers) > 0; + + return [] !== $this->authorizationHelper->getReachableCenters($token->getUser(), $attribute); } } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php index 1e2f9c02b..e6cdd8b0c 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverDispatcher.php @@ -1,27 +1,43 @@ resolvers = $resolvers; } /** - * @param mixed $entity - * @param array|null $options + * @param object $entity * @return null|Center|Center[] */ public function resolveCenter($entity, ?array $options = []) { - foreach($this->resolvers as $priority => $resolver) { + trigger_deprecation( + 'ChillMainBundle', + 'dev-master', + ' + Use the service CenterResolverManager through the interface CenterResolverManagerInterface. + The new method "CenterResolverManagerInterface::resolveCenters(): array" is available and the typing + has been improved in order to avoid mixing types. + ' + ); + + foreach($this->resolvers as $resolver) { if ($resolver->supports($entity, $options)) { return $resolver->resolveCenter($entity, $options); } diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverInterface.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverInterface.php index db49874b7..f3bf44b5a 100644 --- a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverInterface.php @@ -6,12 +6,14 @@ use Chill\MainBundle\Entity\Center; interface CenterResolverInterface { + /** + * @param object $entity + */ public function supports($entity, ?array $options = []): bool; /** - * @param $entity - * @param array|null $options - * @return Center|array|Center[] + * @param object $entity + * @return Center|Center[] */ public function resolveCenter($entity, ?array $options = []); diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManager.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManager.php new file mode 100644 index 000000000..2dc947c8b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManager.php @@ -0,0 +1,29 @@ +resolvers = $resolvers; + } + + public function resolveCenters($entity, ?array $options = []): array + { + foreach($this->resolvers as $resolver) { + if ($resolver->supports($entity, $options)) { + return (array) $resolver->resolveCenter($entity, $options); + } + } + + return []; + } +} diff --git a/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php new file mode 100644 index 000000000..1ca145b99 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Security/Resolver/CenterResolverManagerInterface.php @@ -0,0 +1,16 @@ + - * - * 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 . - */ + +declare(strict_types=1); namespace Chill\MainBundle\Templating; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Translation\Translator; +use Symfony\Contracts\Translation\TranslatorInterface; -/** - * - * This helper helps to find the string in current locale from translatable_strings - * - * @author Julien Fastré - * - */ -class TranslatableStringHelper +final class TranslatableStringHelper implements TranslatableStringHelperInterface { - /** - * - * @var RequestStack - */ - private $requestStack; - - private $fallbackLocales; - - public function __construct(RequestStack $requestStack, Translator $translator) + private RequestStack $requestStack; + + private TranslatorInterface $translator; + + public function __construct(RequestStack $requestStack, TranslatorInterface $translator) { $this->requestStack = $requestStack; - $this->fallbackLocales = $translator->getFallbackLocales(); + $this->translator = $translator; } - - /** - * return the string in current locale if it exists. - * - * If it does not exists; return the name in the first language available. - * - * Return a blank string if any strings are available. - * Return NULL if $translatableString is NULL - * - * @param array $translatableStrings - * @return string - */ - public function localize(array $translatableStrings) - { - if (NULL === $translatableStrings) { - return NULL; - } - - $language = $this->requestStack->getCurrentRequest()->getLocale(); - - if (isset($translatableStrings[$language])) { - - return $translatableStrings[$language]; - } else { - foreach ($this->fallbackLocales as $locale) { - if (array_key_exists($locale, $translatableStrings)) { - - return $translatableStrings[$locale]; - } - } - + public function localize(array $translatableStrings): ?string + { + if ([] === $translatableStrings) { + return null; } - + + $request = $this->requestStack->getCurrentRequest(); + + if (null === $request) { + return null; + } + + $language = $request->getLocale(); + + if (array_key_exists($language, $translatableStrings)) { + return $translatableStrings[$language]; + } + + foreach ($this->translator->getFallbackLocales() as $locale) { + if (array_key_exists($locale, $translatableStrings)) { + return $translatableStrings[$locale]; + } + } + // no fallback translation... trying the first available $langs = array_keys($translatableStrings); - - if (count($langs) === 0) { + + if ([] === $langs) { return ''; } - - return $translatableStrings[$langs[0]]; + return $translatableStrings[$langs[0]]; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelperInterface.php b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelperInterface.php new file mode 100644 index 000000000..72e9397f8 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelperInterface.php @@ -0,0 +1,17 @@ +id; } diff --git a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php index 1f21defd9..430514d21 100644 --- a/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php +++ b/src/Bundle/ChillPersonBundle/Form/SocialWork/SocialIssueType.php @@ -1,83 +1,49 @@ - * - * 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 . - */ + +declare(strict_types=1); + namespace Chill\PersonBundle\Form\SocialWork; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Chill\MainBundle\Form\Type\TranslatableStringFormType; use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; -/** - * Class SocialIssueType - * - * @package Chill\PersonBundle\Form - */ class SocialIssueType extends AbstractType { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; + protected TranslatableStringHelperInterface $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) { + public function __construct( + TranslatableStringHelperInterface $translatableStringHelper + ) { $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', TranslatableStringFormType::class, [ 'label' => 'Nom' ]) - ->add('parent', EntityType::class, [ 'class' => SocialIssue::class, 'required' => false, - 'choice_label' => function (SocialIssue $issue) { - return $this->translatableStringHelper->localize($issue->getTitle()); - } + 'choice_label' => fn (SocialIssue $issue): ?string => $this->translatableStringHelper->localize($issue->getTitle()) ]) - ->add('desactivationDate', DateType::class, [ 'attr' => ['class' => 'datepicker'], 'widget'=> 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, ]); -} + } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { - $resolver - ->setDefault('class', SocialIssue::class) - ; + $resolver->setDefault('class', SocialIssue::class); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php index 8cd0e6b83..a237b3571 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/Person/PersonHasCenterValidatorTest.php @@ -1,14 +1,18 @@ [ 'center_required' => true ] - ]) - ; + ]); - return new PersonHasCenterValidator($parameterBag); + $centerResolverDispatcher = $this->createMock(CenterResolverDispatcher::class); + + return new PersonHasCenterValidator($parameterBag, $centerResolverDispatcher); } } diff --git a/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php b/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php index a0e77bbaa..04f4ba346 100644 --- a/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php +++ b/src/Bundle/ChillReportBundle/Timeline/TimelineReportProvider.php @@ -22,7 +22,6 @@ use Chill\MainBundle\Timeline\TimelineSingleQuery; */ class TimelineReportProvider implements TimelineProviderInterface { - protected EntityManager $em; protected AuthorizationHelper $helper; @@ -84,11 +83,12 @@ class TimelineReportProvider implements TimelineProviderInterface private function getWhereClauseForCenter(string $context, array $args): array { + $role = 'CHILL_REPORT_SEE'; + $report = $this->em->getClassMetadata(Report::class); $person = $this->em->getClassMetadata(Person::class); - $role = new Role('CHILL_REPORT_SEE'); - $reachableCenters = $this->helper->getReachableCenters($this->security->getUser(), - $role); + + $reachableCenters = $this->helper->getReachableCenters($this->security->getUser(), $role); $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; @@ -111,8 +111,7 @@ class TimelineReportProvider implements TimelineProviderInterface $parameters[] = $center->getId(); // loop over scopes $scopeIds = []; - foreach ($this->helper->getReachableScopes($this->security->getUser(), - $role, $center) as $scope) { + foreach ($this->helper->getReachableScopes($this->security->getUser(), $role, $center) as $scope) { if (\in_array($scope->getId(), $scopeIds)) { continue; } @@ -146,9 +145,9 @@ class TimelineReportProvider implements TimelineProviderInterface private function getWhereClauseForPerson(string $context, array $args): array { + $role = 'CHILL_REPORT_SEE'; $report = $this->em->getClassMetadata(Report::class); $person = $this->em->getClassMetadata(Person::class); - $role = new Role('CHILL_REPORT_SEE'); $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; @@ -158,8 +157,7 @@ class TimelineReportProvider implements TimelineProviderInterface // this is the final clause that we are going to fill $clause = "{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})"; // iterate over reachable scopes - $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, - $args['person']->getCenter()); + $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, $args['person']->getCenter()); foreach ($scopes as $scope) { if (\in_array($scope->getId(), $parameters)) { diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php index 85fe632b7..9af1197c2 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php @@ -52,7 +52,8 @@ class SingleTaskType extends AbstractType 'required' => false, 'center' => $center, 'role' => TaskVoter::SHOW, - 'placeholder' => 'Not assigned' + 'placeholder' => 'Not assigned', + 'attr' => [ 'class' => ' select2 '] ]) ->add('startDate', ChillDateType::class, [ 'required' => false