Merge branch 'master' into 295_resume_retouches

This commit is contained in:
Mathieu Jaumotte 2021-11-19 17:22:00 +01:00
commit 89c2d74c33
65 changed files with 1021 additions and 1351 deletions

View File

@ -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 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 * [person] do not ask for center any more on person creation
* [3party] do not ask for center any more on 3party 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 ## Test releases

View File

@ -129,4 +129,3 @@ parameters:
message: "#^Call to an undefined method Chill\\\\ThirdPartyBundle\\\\Form\\\\Type\\\\PickThirdPartyTypeCategoryType\\:\\:transform\\(\\)\\.$#" message: "#^Call to an undefined method Chill\\\\ThirdPartyBundle\\\\Form\\\\Type\\\\PickThirdPartyTypeCategoryType\\:\\:transform\\(\\)\\.$#"
count: 1 count: 1
path: src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php path: src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php

View File

@ -5,18 +5,21 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Controller; namespace Chill\ActivityBundle\Controller;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Chill\ActivityBundle\Repository\ActivityACLAwareRepositoryInterface; 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\ActivityBundle\Security\Authorization\ActivityVoter;
use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Repository\LocationRepository;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Privacy\PrivacyEvent; 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 Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -30,26 +33,54 @@ use Symfony\Component\Serializer\SerializerInterface;
final class ActivityController extends AbstractController 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( public function __construct(
ActivityACLAwareRepositoryInterface $activityACLAwareRepository, ActivityACLAwareRepositoryInterface $activityACLAwareRepository,
ActivityTypeRepository $activityTypeRepository,
ActivityTypeCategoryRepository $activityTypeCategoryRepository,
PersonRepository $personRepository,
ThirdPartyRepository $thirdPartyRepository,
LocationRepository $locationRepository,
ActivityRepository $activityRepository,
AccompanyingPeriodRepository $accompanyingPeriodRepository,
EntityManagerInterface $entityManager,
EventDispatcherInterface $eventDispatcher, EventDispatcherInterface $eventDispatcher,
AuthorizationHelper $authorizationHelper,
LoggerInterface $logger, LoggerInterface $logger,
SerializerInterface $serializer SerializerInterface $serializer
) { ) {
$this->activityACLAwareRepository = $activityACLAwareRepository; $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->eventDispatcher = $eventDispatcher;
$this->authorizationHelper = $authorizationHelper;
$this->logger = $logger; $this->logger = $logger;
$this->serializer = $serializer; $this->serializer = $serializer;
} }
@ -98,7 +129,6 @@ final class ActivityController extends AbstractController
public function selectTypeAction(Request $request): Response public function selectTypeAction(Request $request): Response
{ {
$em = $this->getDoctrine()->getManager();
$view = null; $view = null;
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -111,12 +141,17 @@ final class ActivityController extends AbstractController
$data = []; $data = [];
$activityTypeCategories = $em->getRepository(ActivityTypeCategory::class) $activityTypeCategories = $this
->activityTypeCategoryRepository
->findBy(['active' => true], ['ordering' => 'ASC']); ->findBy(['active' => true], ['ordering' => 'ASC']);
foreach ($activityTypeCategories as $activityTypeCategory) { foreach ($activityTypeCategories as $activityTypeCategory) {
$activityTypes = $em->getRepository(ActivityType::class) $activityTypes = $this
->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']); ->activityTypeRepository
->findBy(
['active' => true, 'category' => $activityTypeCategory],
['ordering' => 'ASC']
);
$data[] = [ $data[] = [
'activityTypeCategory' => $activityTypeCategory, 'activityTypeCategory' => $activityTypeCategory,
@ -139,7 +174,6 @@ final class ActivityController extends AbstractController
public function newAction(Request $request): Response public function newAction(Request $request): Response
{ {
$view = null; $view = null;
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -150,8 +184,7 @@ final class ActivityController extends AbstractController
} }
$activityType_id = $request->get('activityType_id', 0); $activityType_id = $request->get('activityType_id', 0);
$activityType = $em->getRepository(ActivityType::class) $activityType = $this->activityTypeRepository->find($activityType_id);
->find($activityType_id);
if (isset($activityType) && !$activityType->isActive()) { if (isset($activityType) && !$activityType->isActive()) {
throw new \InvalidArgumentException('Activity type must be active'); throw new \InvalidArgumentException('Activity type must be active');
@ -209,20 +242,20 @@ final class ActivityController extends AbstractController
if (array_key_exists('personsId', $activityData)) { if (array_key_exists('personsId', $activityData)) {
foreach($activityData['personsId'] as $personId){ foreach($activityData['personsId'] as $personId){
$concernedPerson = $em->getRepository(Person::class)->find($personId); $concernedPerson = $this->personRepository->find($personId);
$entity->addPerson($concernedPerson); $entity->addPerson($concernedPerson);
} }
} }
if (array_key_exists('professionalsId', $activityData)) { if (array_key_exists('professionalsId', $activityData)) {
foreach($activityData['professionalsId'] as $professionalsId){ foreach($activityData['professionalsId'] as $professionalsId){
$professional = $em->getRepository(ThirdParty::class)->find($professionalsId); $professional = $this->thirdPartyRepository->find($professionalsId);
$entity->addThirdParty($professional); $entity->addThirdParty($professional);
} }
} }
if (array_key_exists('location', $activityData)) { if (array_key_exists('location', $activityData)) {
$location = $em->getRepository(Location::class)->find($activityData['location']); $location = $this->locationRepository->find($activityData['location']);
$entity->setLocation($location); $entity->setLocation($location);
} }
@ -247,8 +280,8 @@ final class ActivityController extends AbstractController
])->handleRequest($request); ])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity); $this->entityManager->persist($entity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); $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 public function showAction(Request $request, $id): Response
{ {
$view = null; $view = null;
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -287,8 +319,7 @@ final class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:showPerson.html.twig'; $view = 'ChillActivityBundle:Activity:showPerson.html.twig';
} }
/** @var Activity $entity */ $entity = $this->activityRepository->find($id);
$entity = $em->getRepository(Activity::class)->find($id);
if (null === $entity) { if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity 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 public function editAction($id, Request $request): Response
{ {
$view = null; $view = null;
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -343,8 +373,7 @@ final class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:editPerson.html.twig'; $view = 'ChillActivityBundle:Activity:editPerson.html.twig';
} }
/** @var Activity $entity */ $entity = $this->activityRepository->find($id);
$entity = $em->getRepository(Activity::class)->find($id);
if (null === $entity) { if (null === $entity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
@ -361,8 +390,8 @@ final class ActivityController extends AbstractController
])->handleRequest($request); ])->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em->persist($entity); $this->entityManager->persist($entity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); $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) public function deleteAction(Request $request, $id)
{ {
$view = null; $view = null;
$em = $this->getDoctrine()->getManager();
[$person, $accompanyingPeriod] = $this->getEntity($request); [$person, $accompanyingPeriod] = $this->getEntity($request);
@ -416,8 +444,7 @@ final class ActivityController extends AbstractController
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
} }
/* @var Activity $activity */ $activity = $this->activityRepository->find($id);
$activity = $em->getRepository(Activity::class)->find($id);
if (!$activity) { if (!$activity) {
throw $this->createNotFoundException('Unable to find Activity entity.'); throw $this->createNotFoundException('Unable to find Activity entity.');
@ -449,8 +476,8 @@ final class ActivityController extends AbstractController
'attendee' => $activity->getAttendee() 'attendee' => $activity->getAttendee()
]); ]);
$em->remove($activity); $this->entityManager->remove($activity);
$em->flush(); $this->entityManager->flush();
$this->addFlash('success', $this->get('translator') $this->addFlash('success', $this->get('translator')
->trans("The activity has been successfully removed.")); ->trans("The activity has been successfully removed."));
@ -490,12 +517,11 @@ final class ActivityController extends AbstractController
private function getEntity(Request $request): array private function getEntity(Request $request): array
{ {
$em = $this->getDoctrine()->getManager();
$person = $accompanyingPeriod = null; $person = $accompanyingPeriod = null;
if ($request->query->has('person_id')) { if ($request->query->has('person_id')) {
$person_id = $request->get('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) { if ($person === null) {
throw $this->createNotFoundException('Person not found'); throw $this->createNotFoundException('Person not found');
@ -504,7 +530,7 @@ final class ActivityController extends AbstractController
$this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person);
} elseif ($request->query->has('accompanying_period_id')) { } elseif ($request->query->has('accompanying_period_id')) {
$accompanying_period_id = $request->get('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) { if ($accompanyingPeriod === null) {
throw $this->createNotFoundException('Accompanying Period not found'); 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 = []; $params = [];
if (null !== $person) { if (null !== $person) {

View File

@ -1,31 +1,12 @@
<?php <?php
/* declare(strict_types=1);
*
* Copyright (C) 2015, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Entity; namespace Chill\ActivityBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
/** /**
* Class ActivityTypeCateogry
*
* @package Chill\ActivityBundle\Entity
* @ORM\Entity() * @ORM\Entity()
* @ORM\Table(name="activitytypecategory") * @ORM\Table(name="activitytypecategory")
* @ORM\HasLifecycleCallbacks() * @ORM\HasLifecycleCallbacks()
@ -37,7 +18,7 @@ class ActivityTypeCategory
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private ?int $id; private ?int $id = null;
/** /**
* @ORM\Column(type="json") * @ORM\Column(type="json")
@ -54,10 +35,7 @@ class ActivityTypeCategory
*/ */
private float $ordering = 0.0; private float $ordering = 0.0;
/** public function getId(): ?int
* Get id
*/
public function getId(): int
{ {
return $this->id; return $this->id;
} }

View File

@ -1,70 +1,39 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; 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 Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
/** class ActivityReasonAggregator implements AggregatorInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonAggregator implements AggregatorInterface,
ExportElementValidatedInterface
{ {
/** protected ActivityReasonCategoryRepository $activityReasonCategoryRepository;
*
* @var EntityRepository
*/
protected $categoryRepository;
/** protected ActivityReasonRepository $activityReasonRepository;
*
* @var EntityRepository
*/
protected $reasonRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
public function __construct( public function __construct(
EntityRepository $categoryRepository, ActivityReasonCategoryRepository $activityReasonCategoryRepository,
EntityRepository $reasonRepository, ActivityReasonRepository $activityReasonRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelper $translatableStringHelper
) { ) {
$this->categoryRepository = $categoryRepository; $this->activityReasonCategoryRepository = $activityReasonCategoryRepository;
$this->reasonRepository = $reasonRepository; $this->activityReasonRepository = $activityReasonRepository;
$this->stringHelper = $stringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
@ -77,7 +46,7 @@ class ActivityReasonAggregator implements AggregatorInterface,
$elem = 'category.id'; $elem = 'category.id';
$alias = 'activity_categories_id'; $alias = 'activity_categories_id';
} else { } else {
throw new \RuntimeException('the data provided are not recognized'); throw new \RuntimeException('The data provided are not recognized.');
} }
$qb->addSelect($elem.' as '.$alias); $qb->addSelect($elem.' as '.$alias);
@ -93,11 +62,12 @@ class ActivityReasonAggregator implements AggregatorInterface,
(! array_key_exists('activity', $join)) (! array_key_exists('activity', $join))
) { ) {
$qb->add( $qb->add(
'join', 'join',
array('activity' => [
new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') 'activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')
), ],
true); true
);
} }
// join category if necessary // join category if necessary
@ -143,28 +113,33 @@ class ActivityReasonAggregator implements AggregatorInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('level', ChoiceType::class, array( $builder->add(
'choices' => array( 'level',
'By reason' => 'reasons', ChoiceType::class,
'By category of reason' => 'categories' [
), 'choices' => [
'multiple' => false, 'By reason' => 'reasons',
'expanded' => true, 'By category of reason' => 'categories'
'label' => 'Reason\'s level' ],
)); 'multiple' => false,
'expanded' => true,
'label' => "Reason's level"
]
);
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['level'] === null) { 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(); ->addViolation();
} }
} }
public function getTitle() public function getTitle()
{ {
return "Aggregate by activity reason"; return 'Aggregate by activity reason';
} }
public function addRole() public function addRole()
@ -177,41 +152,33 @@ class ActivityReasonAggregator implements AggregatorInterface,
// for performance reason, we load data from db only once // for performance reason, we load data from db only once
switch ($data['level']) { switch ($data['level']) {
case 'reasons': case 'reasons':
$this->reasonRepository->findBy(array('id' => $values)); $this->activityReasonRepository->findBy(['id' => $values]);
break; break;
case 'categories': case 'categories':
$this->categoryRepository->findBy(array('id' => $values)); $this->activityReasonCategoryRepository->findBy(['id' => $values]);
break; break;
default: default:
throw new \RuntimeException(sprintf("the level data '%s' is invalid", throw new \RuntimeException(sprintf("The level data '%s' is invalid.", $data['level']));
$data['level']));
} }
return function($value) use ($data) { return function($value) use ($data) {
if ($value === '_header') { if ($value === '_header') {
return $data['level'] === 'reasons' ? return $data['level'] === 'reasons' ? 'Group by reasons' : 'Group by categories of reason';
'Group by reasons'
:
'Group by categories of reason'
;
} }
switch ($data['level']) { switch ($data['level']) {
case 'reasons': case 'reasons':
/* @var $r \Chill\ActivityBundle\Entity\ActivityReason */ $r = $this->activityReasonRepository->find($value);
$r = $this->reasonRepository->find($value);
return $this->stringHelper->localize($r->getCategory()->getName()) return sprintf(
." > " "%s > %s",
. $this->stringHelper->localize($r->getName()); $this->translatableStringHelper->localize($r->getCategory()->getName()),
; $this->translatableStringHelper->localize($r->getName())
break; );
case 'categories': case 'categories':
$c = $this->categoryRepository->find($value); $c = $this->activityReasonCategoryRepository->find($value);
return $this->stringHelper->localize($c->getName()); return $this->translatableStringHelper->localize($c->getName());
break;
// no need for a default : the default was already set above
} }
}; };
@ -222,12 +189,14 @@ class ActivityReasonAggregator implements AggregatorInterface,
// add select element // add select element
if ($data['level'] === 'reasons') { if ($data['level'] === 'reasons') {
return array('activity_reasons_id'); 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.');
} }
} }

View File

@ -1,61 +1,32 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityTypeAggregator implements AggregatorInterface class ActivityTypeAggregator implements AggregatorInterface
{ {
protected ActivityTypeRepository $activityTypeRepository;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var EntityRepository
*/
protected $typeRepository;
/** public const KEY = 'activity_type_aggregator';
*
* @var TranslatableStringHelper
*/
protected $stringHelper;
const KEY = 'activity_type_aggregator';
public function __construct( public function __construct(
EntityRepository $typeRepository, ActivityTypeRepository $activityTypeRepository,
TranslatableStringHelper $stringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->typeRepository = $typeRepository; $this->activityTypeRepository = $activityTypeRepository;
$this->stringHelper = $stringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
@ -64,7 +35,7 @@ class ActivityTypeAggregator implements AggregatorInterface
$qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY));
// add the "group by" part // 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() public function getTitle()
{ {
return "Aggregate by activity type"; return 'Aggregate by activity type';
} }
public function addRole() public function addRole()
@ -108,17 +79,16 @@ class ActivityTypeAggregator implements AggregatorInterface
public function getLabels($key, array $values, $data): \Closure public function getLabels($key, array $values, $data): \Closure
{ {
// for performance reason, we load data from db only once // 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 { return function($value): string {
if ($value === '_header') { if ($value === '_header') {
return 'Activity type'; return 'Activity type';
} }
/* @var $r \Chill\ActivityBundle\Entity\ActivityType */ $t = $this->activityTypeRepository->find($value);
$t = $this->typeRepository->find($value);
return $this->stringHelper->localize($t->getName()); return $this->translatableStringHelper->localize($t->getName());
}; };
} }

View File

@ -1,51 +1,26 @@
<?php <?php
/*
* Copyright (C) 2019 Champs Libres Cooperative <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Aggregator; namespace Chill\ActivityBundle\Export\Aggregator;
use Chill\MainBundle\Repository\UserRepository;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\AggregatorInterface;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query\Expr\Join;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
use Chill\MainBundle\Entity\User;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityUserAggregator implements AggregatorInterface class ActivityUserAggregator implements AggregatorInterface
{ {
/** public const KEY = 'activity_user_id';
*
* @var EntityManagerInterface private UserRepository $userRepository;
*/
protected $em; public function __construct(
UserRepository $userRepository
const KEY = 'activity_user_id'; ) {
$this->userRepository = $userRepository;
function __construct(EntityManagerInterface $em)
{
$this->em = $em;
} }
public function addRole() public function addRole()
{ {
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
@ -53,9 +28,9 @@ class ActivityUserAggregator implements AggregatorInterface
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// add select element // add select element
$qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY)); $qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY));
// add the "group by" part // add the "group by" part
$qb->addGroupBy(self::KEY); $qb->addGroupBy(self::KEY);
} }
@ -73,17 +48,14 @@ class ActivityUserAggregator implements AggregatorInterface
public function getLabels($key, $values, $data): \Closure public function getLabels($key, $values, $data): \Closure
{ {
// preload users at once // preload users at once
$this->em->getRepository(User::class) $this->userRepository->findBy(['id' => $values]);
->findBy(['id' => $values]);
return function($value) { return function($value) {
switch ($value) { if ($value === '_header') {
case '_header': return 'activity user';
return 'activity user';
default:
return $this->em->getRepository(User::class)->find($value)
->getUsername();
} }
return $this->userRepository->find($value)->getUsername();
}; };
} }
@ -94,6 +66,6 @@ class ActivityUserAggregator implements AggregatorInterface
public function getTitle(): string public function getTitle(): string
{ {
return "Aggregate by activity user"; return 'Aggregate by activity user';
} }
} }

View File

@ -1,64 +1,40 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2015 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ExportInterface; 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 Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class CountActivity implements ExportInterface class CountActivity implements ExportInterface
{ {
/** protected ActivityRepository $activityRepository;
*
* @var EntityManagerInterface
*/
protected $entityManager;
public function __construct( public function __construct(
EntityManagerInterface $em ActivityRepository $activityRepository
) ) {
{ $this->activityRepository = $activityRepository;
$this->entityManager = $em;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
} }
public function getDescription() public function getDescription()
{ {
return "Count activities by various parameters."; return 'Count activities by various parameters.';
} }
public function getTitle() public function getTitle()
{ {
return "Count activities"; return 'Count activities';
} }
public function getType() public function getType()
@ -68,26 +44,26 @@ class CountActivity implements ExportInterface
public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) public function initiateQuery(array $requiredModifiers, array $acl, array $data = array())
{ {
$qb = $this->entityManager->createQueryBuilder(); $centers = array_map(static fn($el) => $el['center'], $acl);
$centers = array_map(function($el) { return $el['center']; }, $acl);
$qb = $this
$qb->select('COUNT(activity.id) as export_count_activity') ->activityRepository
->from('ChillActivityBundle:Activity', 'activity') ->createQueryBuilder('activity')
->join('activity.person', 'person') ->select('COUNT(activity.id) as export_count_activity')
; ->join('activity.person', 'person');
$qb->where($qb->expr()->in('person.center', ':centers')) $qb
->setParameter('centers', $centers) ->where($qb->expr()->in('person.center', ':centers'))
; ->setParameter('centers', $centers);
return $qb; return $qb;
} }
public function supportsModifiers() public function supportsModifiers()
{ {
return array('person', 'activity'); return ['person', 'activity'];
} }
public function requiredRole() public function requiredRole()
{ {
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
@ -95,7 +71,7 @@ class CountActivity implements ExportInterface
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [FormatterInterface::TYPE_TABULAR];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)
@ -103,19 +79,13 @@ class CountActivity implements ExportInterface
if ($key !== 'export_count_activity') { if ($key !== 'export_count_activity') {
throw new \LogicException("the key $key is not used by this export"); throw new \LogicException("the key $key is not used by this export");
} }
return function($value) { return static fn($value) => $value === '_header' ? 'Number of activities' : $value;
return $value === '_header' ?
'Number of activities'
:
$value
;
};
} }
public function getQueryKeys($data) public function getQueryKeys($data)
{ {
return array('export_count_activity'); return ['export_count_activity'];
} }
public function getResult($qb, $data) public function getResult($qb, $data)

View File

@ -1,31 +1,14 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ListInterface; use Chill\MainBundle\Export\ListInterface;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Entity\Scope; use Doctrine\DBAL\Exception\InvalidArgumentException;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Symfony\Component\Form\FormBuilderInterface; 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\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* Create a list for all activities
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ListActivity implements ListInterface class ListActivity implements ListInterface
{ {
private ActivityRepository $activityRepository;
/** protected EntityManagerInterface $entityManager;
*
* @var EntityManagerInterface
*/
protected $entityManager;
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $fields = array( protected array $fields = [
'id', 'id',
'date', 'date',
'durationTime', 'durationTime',
@ -75,32 +42,28 @@ class ListActivity implements ListInterface
'person_firstname', 'person_firstname',
'person_lastname', 'person_lastname',
'person_id' 'person_id'
); ];
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $em,
TranslatorInterface $translator, TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper,
) ActivityRepository $activityRepository
{ ) {
$this->entityManager = $em; $this->entityManager = $em;
$this->translator = $translator; $this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityRepository = $activityRepository;
} }
/**
* {@inheritDoc}
*
* @param FormBuilderInterface $builder
*/
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('fields', ChoiceType::class, array( $builder->add('fields', ChoiceType::class, [
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
'choices' => array_combine($this->fields, $this->fields), 'choices' => array_combine($this->fields, $this->fields),
'label' => 'Fields to include in export', 'label' => 'Fields to include in export',
'constraints' => [new Callback(array( 'constraints' => [new Callback([
'callback' => function($selected, ExecutionContextInterface $context) { 'callback' => function($selected, ExecutionContextInterface $context) {
if (count($selected) === 0) { if (count($selected) === 0) {
$context->buildViolation('You must select at least one element') $context->buildViolation('You must select at least one element')
@ -108,19 +71,14 @@ class ListActivity implements ListInterface
->addViolation(); ->addViolation();
} }
} }
))] ])]
)); ]);
} }
/**
* {@inheritDoc}
*
* @return type
*/
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(FormatterInterface::TYPE_LIST); return [FormatterInterface::TYPE_LIST];
} }
public function getDescription() public function getDescription()
@ -133,29 +91,32 @@ class ListActivity implements ListInterface
switch ($key) switch ($key)
{ {
case 'date' : case 'date' :
return function($value) { return static function($value) {
if ($value === '_header') return 'date'; if ($value === '_header') {
return 'date';
}
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value); $date = \DateTime::createFromFormat('Y-m-d H:i:s', $value);
return $date->format('d-m-Y'); return $date->format('d-m-Y');
}; };
case 'attendee': case 'attendee':
return function($value) { return static function($value) {
if ($value === '_header') return 'attendee'; if ($value === '_header') {
return 'attendee';
}
return $value ? 1 : 0; return $value ? 1 : 0;
}; };
case 'list_reasons' : case 'list_reasons' :
/* @var $activityReasonsRepository EntityRepository */ $activityRepository = $this->activityRepository;
$activityRepository = $this->entityManager
->getRepository('ChillActivityBundle:Activity');
return function($value) use ($activityRepository) { return function($value) use ($activityRepository): string {
if ($value === '_header') return 'activity reasons'; if ($value === '_header') {
return 'activity reasons';
}
$activity = $activityRepository $activity = $activityRepository->find($value);
->find($value);
return implode(", ", array_map(function(ActivityReason $r) { return implode(", ", array_map(function(ActivityReason $r) {
@ -168,21 +129,25 @@ class ListActivity implements ListInterface
}; };
case 'circle_name' : case 'circle_name' :
return function($value) { return function($value) {
if ($value === '_header') return 'circle'; if ($value === '_header') {
return 'circle';
}
return $this->translatableStringHelper return $this->translatableStringHelper->localize(json_decode($value, true));
->localize(json_decode($value, true));
}; };
case 'type_name' : case 'type_name' :
return function($value) { return function($value) {
if ($value === '_header') return 'activity type'; if ($value === '_header') {
return 'activity type';
}
return $this->translatableStringHelper return $this->translatableStringHelper->localize(json_decode($value, true));
->localize(json_decode($value, true));
}; };
default: default:
return function($value) use ($key) { return static function($value) use ($key) {
if ($value === '_header') return $key; if ($value === '_header') {
return $key;
}
return $value; return $value;
}; };
@ -209,14 +174,13 @@ class ListActivity implements ListInterface
return 'activity'; 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); $centers = array_map(function($el) { return $el['center']; }, $acl);
// throw an error if any fields are present // throw an error if any fields are present
if (!\array_key_exists('fields', $data)) { if (!\array_key_exists('fields', $data)) {
throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " throw new InvalidArgumentException('Any fields have been checked.');
. "have been checked");
} }
$qb = $this->entityManager->createQueryBuilder(); $qb = $this->entityManager->createQueryBuilder();
@ -227,7 +191,6 @@ class ListActivity implements ListInterface
->join('person.center', 'center') ->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)') ->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers); ->setParameter('authorized_centers', $centers);
;
foreach ($this->fields as $f) { foreach ($this->fields as $f) {
if (in_array($f, $data['fields'])) { if (in_array($f, $data['fields'])) {
@ -269,8 +232,6 @@ class ListActivity implements ListInterface
} }
} }
return $qb; return $qb;
} }
@ -281,7 +242,7 @@ class ListActivity implements ListInterface
public function supportsModifiers() public function supportsModifiers()
{ {
return array('activity', 'person'); return ['activity', 'person'];
} }
} }

View File

@ -4,12 +4,13 @@ declare(strict_types=1);
namespace Chill\ActivityBundle\Export\Export; namespace Chill\ActivityBundle\Export\Export;
use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\MainBundle\Export\ExportInterface; 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 Symfony\Component\Security\Core\Role\Role;
use Doctrine\ORM\Query; use Doctrine\ORM\Query;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityManagerInterface;
/** /**
* This export allow to compute stats on activity duration. * This export allow to compute stats on activity duration.
@ -18,7 +19,7 @@ use Doctrine\ORM\EntityManagerInterface;
*/ */
class StatActivityDuration implements ExportInterface class StatActivityDuration implements ExportInterface
{ {
protected EntityManagerInterface $entityManager; private ActivityRepository $activityRepository;
public const SUM = 'sum'; public const SUM = 'sum';
@ -30,13 +31,15 @@ class StatActivityDuration implements ExportInterface
/** /**
* @param string $action the stat to perform * @param string $action the stat to perform
*/ */
public function __construct(EntityManagerInterface $em, string $action = 'sum') public function __construct(
{ ActivityRepository $activityRepository,
$this->entityManager = $em; string $action = 'sum'
) {
$this->action = $action; $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 $acl
); );
$qb = $this->entityManager->createQueryBuilder(); $qb = $this->activityRepository->createQueryBuilder('activity');
$select = null; $select = null;
@ -77,7 +80,6 @@ class StatActivityDuration implements ExportInterface
} }
return $qb->select($select) return $qb->select($select)
->from('ChillActivityBundle:Activity', 'activity')
->join('activity.person', 'person') ->join('activity.person', 'person')
->join('person.center', 'center') ->join('person.center', 'center')
->where($qb->expr()->in('center', ':centers')) ->where($qb->expr()->in('center', ':centers'))
@ -96,7 +98,7 @@ class StatActivityDuration implements ExportInterface
public function getAllowedFormattersTypes() public function getAllowedFormattersTypes()
{ {
return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); return [FormatterInterface::TYPE_TABULAR];
} }
public function getLabels($key, array $values, $data) public function getLabels($key, array $values, $data)

View File

@ -1,25 +1,12 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType; 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 Doctrine\ORM\Query\Expr;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityDateFilter implements FilterInterface class ActivityDateFilter implements FilterInterface
{ {
/** protected TranslatorInterface $translator;
*
* @var TranslatorInterface
*/
protected $translator;
function __construct(TranslatorInterface $translator) function __construct(TranslatorInterface $translator)
{ {
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
} }
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$clause = $qb->expr()->between('activity.date', ':date_from', $clause = $qb->expr()->between('activity.date', ':date_from',
':date_to'); ':date_to');
if ($where instanceof Expr\Andx) { if ($where instanceof Expr\Andx) {
@ -63,7 +40,7 @@ class ActivityDateFilter implements FilterInterface
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('date_from', $data['date_from']); $qb->setParameter('date_from', $data['date_from']);
$qb->setParameter('date_to', $data['date_to']); $qb->setParameter('date_to', $data['date_to']);
@ -74,35 +51,43 @@ class ActivityDateFilter implements FilterInterface
return 'activity'; return 'activity';
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
$builder->add('date_from', DateType::class, array( $builder->add(
'label' => "Activities after this date", 'date_from',
'data' => new \DateTime(), DateType::class,
'attr' => array('class' => 'datepicker'), [
'widget'=> 'single_text', 'label' => 'Activities after this date',
'format' => 'dd-MM-yyyy', 'data' => new \DateTime(),
)); 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text',
$builder->add('date_to', DateType::class, array( 'format' => 'dd-MM-yyyy',
'label' => "Activities before this date", ]
'data' => new \DateTime(), );
'attr' => array('class' => 'datepicker'),
'widget'=> 'single_text', $builder->add(
'format' => 'dd-MM-yyyy', '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) { $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var $filterForm \Symfony\Component\Form\FormInterface */
$filterForm = $event->getForm()->getParent(); $filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if ($enabled === true) { if ($enabled === true) {
// if the filter is enabled, add some validation // if the filter is enabled, add some validation
$form = $event->getForm(); $form = $event->getForm();
$date_from = $form->get('date_from')->getData(); $date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData(); $date_to = $form->get('date_to')->getData();
// check that fields are not empty // check that fields are not empty
if ($date_from === null) { if ($date_from === null) {
$form->get('date_from')->addError(new FormError( $form->get('date_from')->addError(new FormError(
@ -113,8 +98,8 @@ class ActivityDateFilter implements FilterInterface
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')));
} }
// check that date_from is before date_to // check that date_from is before date_to
if ( if (
($date_from !== null && $date_to !== null) ($date_from !== null && $date_to !== null)
@ -132,17 +117,18 @@ class ActivityDateFilter implements FilterInterface
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by date of activity: only between %date_from% and %date_to%", 'Filtered by date of activity: only between %date_from% and %date_to%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y') '%date_to%' => $data['date_to']->format('d-m-Y')
)); ]
];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by date activity"; return 'Filtered by date activity';
} }
} }

View File

@ -1,25 +1,12 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2016 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
@ -28,41 +15,24 @@ use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
/** class ActivityReasonFilter implements FilterInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ActivityReasonFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper protected ActivityReasonRepository $activityReasonRepository;
*/
protected $translatableStringHelper;
/**
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $reasonRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelper $helper,
EntityRepository $reasonRepository ActivityReasonRepository $activityReasonRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->reasonRepository = $reasonRepository; $this->activityReasonRepository = $activityReasonRepository;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@ -75,12 +45,12 @@ class ActivityReasonFilter implements FilterInterface,
&& &&
!$this->checkJoinAlreadyDefined($join['activity'], 'reasons') !$this->checkJoinAlreadyDefined($join['activity'], 'reasons')
) )
OR ||
(! array_key_exists('activity', $join)) (! array_key_exists('activity', $join))
) { ) {
$qb->add( $qb->add(
'join', 'join',
array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')), array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')),
true true
); );
} }
@ -90,25 +60,25 @@ class ActivityReasonFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('selected_activity_reasons', $data['reasons']); $qb->setParameter('selected_activity_reasons', $data['reasons']);
} }
/** /**
* Check if a join between Activity and Reason is already defined * Check if a join between Activity and Reason is already defined
* *
* @param Join[] $joins * @param Join[] $joins
* @return boolean * @return boolean
*/ */
private function checkJoinAlreadyDefined(array $joins, $alias) private function checkJoinAlreadyDefined(array $joins, $alias): bool
{ {
foreach ($joins as $join) { foreach ($joins as $join) {
if ($join->getAlias() === $alias) { if ($join->getAlias() === $alias) {
return true; return true;
} }
} }
return false; return false;
} }
@ -119,51 +89,47 @@ class ActivityReasonFilter implements FilterInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
//create a local copy of translatableStringHelper $builder->add('reasons', EntityType::class, [
$helper = $this->translatableStringHelper; 'class' => ActivityReason::class,
'choice_label' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getName()),
$builder->add('reasons', EntityType::class, array( 'group_by' => fn(ActivityReason $reason) => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
'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());
},
'multiple' => true, 'multiple' => true,
'expanded' => false 'expanded' => false
)); ]);
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['reasons'] === null || count($data['reasons']) === 0) { 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(); ->addViolation();
} }
} }
public function getTitle() public function getTitle()
{ {
return 'Filter by reason'; return 'Filter by reason';
} }
public function addRole() public function addRole()
{ {
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
} }
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityReason $r) { fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
return "\"".$this->translatableStringHelper->localize($r->getName())."\""; $this->activityReasonRepository->findBy(array('id' => $data['reasons']->toArray()))
}, );
$this->reasonRepository->findBy(array('id' => $data['reasons']->toArray()))
); return [
'Filtered by reasons: only %list%',
return array("Filtered by reasons: only %list%", [
["%list%" => implode(", ", $reasonsNames)]); '%list%' => implode(", ", $reasonsNames),
]
];
} }
} }

View File

@ -1,67 +1,37 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2018 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityTypeRepository;
use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FilterInterface;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;
use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\Role;
use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join; use Doctrine\ORM\Query\Expr\Join;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
/** class ActivityTypeFilter implements FilterInterface, ExportElementValidatedInterface
*
*
*/
class ActivityTypeFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper protected ActivityTypeRepository $activityTypeRepository;
*/
protected $translatableStringHelper;
/**
* The repository for activity reasons
*
* @var EntityRepository
*/
protected $typeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelperInterface $translatableStringHelper,
EntityRepository $typeRepository ActivityTypeRepository $activityTypeRepository
) { ) {
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $translatableStringHelper;
$this->typeRepository = $typeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
public function alterQuery(QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
@ -72,14 +42,14 @@ class ActivityTypeFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('selected_activity_types', $data['types']); $qb->setParameter('selected_activity_types', $data['types']);
} }
/** /**
* Check if a join between Activity and Reason is already defined * Check if a join between Activity and Reason is already defined
* *
* @param Join[] $joins * @param Join[] $joins
* @return boolean * @return boolean
*/ */
@ -90,7 +60,7 @@ class ActivityTypeFilter implements FilterInterface,
return true; return true;
} }
} }
return false; return false;
} }
@ -101,48 +71,50 @@ class ActivityTypeFilter implements FilterInterface,
public function buildForm(FormBuilderInterface $builder) public function buildForm(FormBuilderInterface $builder)
{ {
//create a local copy of translatableStringHelper $builder->add(
$helper = $this->translatableStringHelper; 'types',
EntityType::class,
$builder->add('types', EntityType::class, array( [
'class' => ActivityType::class, 'class' => ActivityType::class,
'choice_label' => function (ActivityType $type) use ($helper) { 'choice_label' => fn(ActivityType $type) => $this->translatableStringHelper->localize($type->getName()),
return $helper->localize($type->getName()); 'multiple' => true,
}, 'expanded' => false
'multiple' => true, ]
'expanded' => false );
));
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['types'] === null || count($data['types']) === 0) { 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(); ->addViolation();
} }
} }
public function getTitle() public function getTitle()
{ {
return 'Filter by activity type'; return 'Filter by activity type';
} }
public function addRole() public function addRole()
{ {
return new Role(ActivityStatsVoter::STATS); return new Role(ActivityStatsVoter::STATS);
} }
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
// collect all the reasons'name used in this filter in one array // collect all the reasons'name used in this filter in one array
$reasonsNames = array_map( $reasonsNames = array_map(
function(ActivityType $t) { fn(ActivityType $t): string => '"' . $this->translatableStringHelper->localize($t->getName()) . '"',
return "\"".$this->translatableStringHelper->localize($t->getName())."\""; $this->activityTypeRepository->findBy(['id' => $data['types']->toArray()])
}, );
$this->typeRepository->findBy(array('id' => $data['types']->toArray()))
); return [
'Filtered by activity type: only %list%',
return array("Filtered by activity type: only %list%", [
["%list%" => implode(", ", $reasonsNames)]); '%list%' => implode(", ", $reasonsNames),
]
];
} }
} }

View File

@ -1,25 +1,14 @@
<?php <?php
/* declare(strict_types=1);
* Copyright (C) 2017 Champs-Libres <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Export\Filter; namespace Chill\ActivityBundle\Export\Filter;
use Chill\ActivityBundle\Repository\ActivityReasonRepository;
use Chill\MainBundle\Export\FilterInterface; 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\FormEvent;
use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
@ -29,78 +18,58 @@ use Doctrine\ORM\Query\Expr;
use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\EntityManager;
use Chill\PersonBundle\Export\Declarations; use Chill\PersonBundle\Export\Declarations;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface;
/** class PersonHavingActivityBetweenDateFilter implements FilterInterface, ExportElementValidatedInterface
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class PersonHavingActivityBetweenDateFilter implements FilterInterface,
ExportElementValidatedInterface
{ {
protected TranslatableStringHelperInterface $translatableStringHelper;
/**
* protected ActivityReasonRepository $activityReasonRepository;
* @var TranslatableStringHelper
*/ protected TranslatorInterface $translator;
protected $translatableStringHelper;
/**
*
* @var EntityRepository
*/
protected $activityReasonRepository;
/**
*
* @var TranslatorInterface
*/
protected $translator;
public function __construct( public function __construct(
TranslatableStringHelper $translatableStringHelper, TranslatableStringHelper $translatableStringHelper,
EntityRepository $activityReasonRepository, ActivityReasonRepository $activityReasonRepository,
TranslatorInterface $translator TranslatorInterface $translator
) { ) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
$this->activityReasonRepository = $activityReasonRepository; $this->activityReasonRepository = $activityReasonRepository;
$this->translator = $translator; $this->translator = $translator;
} }
public function addRole() public function addRole()
{ {
return null; return null;
} }
public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) public function alterQuery(QueryBuilder $qb, $data)
{ {
// create a query for activity // create a query for activity
$sqb = $qb->getEntityManager()->createQueryBuilder(); $sqb = $qb->getEntityManager()->createQueryBuilder();
$sqb->select("person_person_having_activity.id") $sqb->select('person_person_having_activity.id')
->from("ChillActivityBundle:Activity", "activity_person_having_activity") ->from('ChillActivityBundle:Activity', 'activity_person_having_activity')
->join("activity_person_having_activity.person", "person_person_having_activity") ->join('activity_person_having_activity.person', 'person_person_having_activity');
;
// add clause between date // add clause between date
$sqb->where("activity_person_having_activity.date BETWEEN " $sqb->where('activity_person_having_activity.date BETWEEN '
. ":person_having_activity_between_date_from" . ':person_having_activity_between_date_from'
. " AND " . ' AND '
. ":person_having_activity_between_date_to"); . ':person_having_activity_between_date_to');
// add clause activity reason // add clause activity reason
$sqb->join('activity_person_having_activity.reasons', $sqb->join('activity_person_having_activity.reasons', 'reasons_person_having_activity');
'reasons_person_having_activity');
$sqb->andWhere( $sqb->andWhere(
$sqb->expr()->in( $sqb->expr()->in(
'reasons_person_having_activity', 'reasons_person_having_activity', ':person_having_activity_reasons'
":person_having_activity_reasons") )
); );
$where = $qb->getDQLPart('where'); $where = $qb->getDQLPart('where');
$clause = $qb->expr()->in('person.id', $sqb->getDQL()); $clause = $qb->expr()->in('person.id', $sqb->getDQL());
@ -109,11 +78,11 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
} else { } else {
$where = $qb->expr()->andX($clause); $where = $qb->expr()->andX($clause);
} }
$qb->add('where', $where); $qb->add('where', $where);
$qb->setParameter('person_having_activity_between_date_from', $qb->setParameter('person_having_activity_between_date_from',
$data['date_from']); $data['date_from']);
$qb->setParameter('person_having_activity_between_date_to', $qb->setParameter('person_having_activity_between_date_to',
$data['date_to']); $data['date_to']);
$qb->setParameter('person_having_activity_reasons', $data['reasons']); $qb->setParameter('person_having_activity_reasons', $data['reasons']);
} }
@ -123,51 +92,45 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
return Declarations::PERSON_IMPLIED_IN; 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( $builder->add('date_from', DateType::class, [
'label' => "Implied in an activity after this date", 'label' => 'Implied in an activity after this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('date_to', DateType::class, array( $builder->add('date_to', DateType::class, [
'label' => "Implied in an activity before this date", 'label' => 'Implied in an activity before this date',
'data' => new \DateTime(), 'data' => new \DateTime(),
'attr' => array('class' => 'datepicker'), 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
)); ]);
$builder->add('reasons', EntityType::class, array( $builder->add('reasons', EntityType::class, [
'class' => 'ChillActivityBundle:ActivityReason', 'class' => ActivityReason::class,
'choice_label' => function (ActivityReason $reason) { 'choice_label' => fn (ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getName()),
return $this->translatableStringHelper 'group_by' => fn(ActivityReason $reason): ?string => $this->translatableStringHelper->localize($reason->getCategory()->getName()),
->localize($reason->getName());
},
'group_by' => function(ActivityReason $reason) {
return $this->translatableStringHelper
->localize($reason->getCategory()->getName());
},
'data' => $this->activityReasonRepository->findAll(), 'data' => $this->activityReasonRepository->findAll(),
'multiple' => true, 'multiple' => true,
'expanded' => false, 'expanded' => false,
'label' => "Activity reasons for those activities" 'label' => 'Activity reasons for those activities'
)); ]);
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
/* @var $filterForm \Symfony\Component\Form\FormInterface */ /* @var FormInterface $filterForm */
$filterForm = $event->getForm()->getParent(); $filterForm = $event->getForm()->getParent();
$enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData();
if ($enabled === true) { if ($enabled === true) {
// if the filter is enabled, add some validation // if the filter is enabled, add some validation
$form = $event->getForm(); $form = $event->getForm();
$date_from = $form->get('date_from')->getData(); $date_from = $form->get('date_from')->getData();
$date_to = $form->get('date_to')->getData(); $date_to = $form->get('date_to')->getData();
// check that fields are not empty // check that fields are not empty
if ($date_from === null) { if ($date_from === null) {
$form->get('date_from')->addError(new FormError( $form->get('date_from')->addError(new FormError(
@ -178,8 +141,8 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
$form->get('date_to')->addError(new FormError( $form->get('date_to')->addError(new FormError(
$this->translator->trans('This field ' $this->translator->trans('This field '
. 'should not be empty'))); . 'should not be empty')));
} }
// check that date_from is before date_to // check that date_from is before date_to
if ( if (
($date_from !== null && $date_to !== null) ($date_from !== null && $date_to !== null)
@ -194,35 +157,37 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface,
} }
}); });
} }
public function validateForm($data, ExecutionContextInterface $context) public function validateForm($data, ExecutionContextInterface $context)
{ {
if ($data['reasons'] === null || count($data['reasons']) === 0) { 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(); ->addViolation();
} }
} }
public function describeAction($data, $format = 'string') public function describeAction($data, $format = 'string')
{ {
return array( return [
"Filtered by person having an activity between %date_from% and " 'Filtered by person having an activity between %date_from% and '
. "%date_to% with reasons %reasons_name%", . '%date_to% with reasons %reasons_name%',
array( [
"%date_from%" => $data['date_from']->format('d-m-Y'), '%date_from%' => $data['date_from']->format('d-m-Y'),
'%date_to%' => $data['date_to']->format('d-m-Y'), '%date_to%' => $data['date_to']->format('d-m-Y'),
"%reasons_name%" => implode(", ", array_map( '%reasons_name%' => implode(
function (ActivityReason $r) { ", ",
return '"'.$this->translatableStringHelper-> array_map(
localize($r->getName()).'"'; fn(ActivityReason $r): string => '"' . $this->translatableStringHelper->localize($r->getName()) . '"',
}, $data['reasons']
$data['reasons'])) )
)); )
]
];
} }
public function getTitle() public function getTitle()
{ {
return "Filtered by person having an activity in a period"; return 'Filtered by person having an activity in a period';
} }
} }

View File

@ -1,56 +1,29 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Form\Type; 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\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
use Chill\ActivityBundle\Entity\ActivityType; use Chill\ActivityBundle\Entity\ActivityType;
/**
* Description of TranslatableActivityType
*
* @author Champs-Libres Coop
*/
class TranslatableActivityType extends AbstractType class TranslatableActivityType extends AbstractType
{ {
protected TranslatableStringHelperInterface $translatableStringHelper;
/** protected ActivityTypeRepository $activityTypeRepository;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
protected $activityTypeRepository;
public function __construct( public function __construct(
TranslatableStringHelper $helper, TranslatableStringHelperInterface $helper,
EntityRepository $activityTypeRepository ActivityTypeRepository $activityTypeRepository
) ) {
{
$this->translatableStringHelper = $helper; $this->translatableStringHelper = $helper;
$this->activityTypeRepository = $activityTypeRepository; $this->activityTypeRepository = $activityTypeRepository;
} }
@ -65,22 +38,21 @@ class TranslatableActivityType extends AbstractType
return EntityType::class; return EntityType::class;
} }
public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) { public function buildForm(FormBuilderInterface $builder, array $options) {
/* @var $qb \Doctrine\ORM\QueryBuilder */ /* @var QueryBuilder $qb */
$qb = $options['query_builder']; $qb = $options['query_builder'];
if ($options['active_only'] === true) { if ($options['active_only'] === true) {
$qb->where($qb->expr()->eq('at.active', ':active')); $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) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults( $resolver->setDefaults(
array( array(
'class' => 'ChillActivityBundle:ActivityType', 'class' => ActivityType::class,
'active_only' => true, 'active_only' => true,
'query_builder' => $this->activityTypeRepository 'query_builder' => $this->activityTypeRepository
->createQueryBuilder('at'), ->createQueryBuilder('at'),

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityReasonCategory;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityReasonCategory|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityReasonCategory|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityReasonCategory[] findAll()
* @method ActivityReasonCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityReasonCategoryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityReasonCategory::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityReason;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityReason|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityReason|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityReason[] findAll()
* @method ActivityReason[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityReasonRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityReason::class);
}
}

View File

@ -1,24 +1,6 @@
<?php <?php
/* declare(strict_types=1);
* Chill is a software for social workers
*
* Copyright (C) 2021, Champs Libres Cooperative SCRLFS,
* <http://www.champs-libres.coop>, <info@champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\ActivityBundle\Repository; namespace Chill\ActivityBundle\Repository;
@ -29,10 +11,10 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
/** /**
* @method AccompanyingPeriodParticipation|null find($id, $lockMode = null, $lockVersion = null) * @method Activity|null find($id, $lockMode = null, $lockVersion = null)
* @method AccompanyingPeriodParticipation|null findOneBy(array $criteria, array $orderBy = null) * @method Activity|null findOneBy(array $criteria, array $orderBy = null)
* @method AccompanyingPeriodParticipation[] findAll() * @method Activity[] findAll()
* @method AccompanyingPeriodParticipation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) * @method Activity[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/ */
class ActivityRepository extends ServiceEntityRepository class ActivityRepository extends ServiceEntityRepository
{ {
@ -42,12 +24,7 @@ class ActivityRepository extends ServiceEntityRepository
} }
/** /**
* @param $person * @return Activity[]
* @param array $scopes
* @param string[] $orderBy
* @param int $limit
* @param int $offset
* @return array|Activity[]
*/ */
public function findByPersonImplied(Person $person, array $scopes, ?array $orderBy = [ 'date' => 'DESC'], ?int $limit = 100, ?int $offset = 0): array 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' ':person MEMBER OF a.persons'
) )
) )
->setParameter('person', $person) ->setParameter('person', $person);
;
foreach ($orderBy as $k => $dir) { foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir); $qb->addOrderBy('a.'.$k, $dir);
@ -72,17 +48,11 @@ class ActivityRepository extends ServiceEntityRepository
$qb->setMaxResults($limit)->setFirstResult($offset); $qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery() return $qb->getQuery()->getResult();
->getResult();
} }
/** /**
* @param AccompanyingPeriod $period * @return Activity[]
* @param array $scopes
* @param int|null $limit
* @param int|null $offset
* @param array|string[] $orderBy
* @return array|Activity[]
*/ */
public function findByAccompanyingPeriod(AccompanyingPeriod $period, array $scopes, ?bool $allowNullScope = false, ?int $limit = 100, ?int $offset = 0, array $orderBy = ['date' => 'desc']): array 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) { if (!$allowNullScope) {
$qb $qb
->where($qb->expr()->in('a.scope', ':scopes')) ->where($qb->expr()->in('a.scope', ':scopes'))
->setParameter('scopes', $scopes) ->setParameter('scopes', $scopes);
;
} else { } else {
$qb $qb
->where( ->where(
@ -102,16 +71,14 @@ class ActivityRepository extends ServiceEntityRepository
$qb->expr()->isNull('a.scope') $qb->expr()->isNull('a.scope')
) )
) )
->setParameter('scopes', $scopes) ->setParameter('scopes', $scopes);
;
} }
$qb $qb
->andWhere( ->andWhere(
$qb->expr()->eq('a.accompanyingPeriod', ':period') $qb->expr()->eq('a.accompanyingPeriod', ':period')
) )
->setParameter('period', $period) ->setParameter('period', $period);
;
foreach ($orderBy as $k => $dir) { foreach ($orderBy as $k => $dir) {
$qb->addOrderBy('a.'.$k, $dir); $qb->addOrderBy('a.'.$k, $dir);
@ -119,7 +86,6 @@ class ActivityRepository extends ServiceEntityRepository
$qb->setMaxResults($limit)->setFirstResult($offset); $qb->setMaxResults($limit)->setFirstResult($offset);
return $qb->getQuery() return $qb->getQuery()->getResult();
->getResult();
} }
} }

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityTypeCategory;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityTypeCategory|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityTypeCategory|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityTypeCategory[] findAll()
* @method ActivityTypeCategory[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityTypeCategoryRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityTypeCategory::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Chill\ActivityBundle\Repository;
use Chill\ActivityBundle\Entity\ActivityType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method ActivityType|null find($id, $lockMode = null, $lockVersion = null)
* @method ActivityType|null findOneBy(array $criteria, array $orderBy = null)
* @method ActivityType[] findAll()
* @method ActivityType[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ActivityTypeRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ActivityType::class);
}
}

View File

@ -79,8 +79,7 @@ class TimelineActivityProvider implements TimelineProviderInterface
$metadataActivity = $this->em->getClassMetadata(Activity::class); $metadataActivity = $this->em->getClassMetadata(Activity::class);
$associationMapping = $metadataActivity->getAssociationMapping('person'); $associationMapping = $metadataActivity->getAssociationMapping('person');
$role = new Role('CHILL_ACTIVITY_SEE'); $role = new Role('CHILL_ACTIVITY_SEE');
$reachableScopes = $this->helper->getReachableScopes($this->user, $reachableScopes = $this->helper->getReachableScopes($this->user, $role->getRole(), $person->getCenter());
$role, $person->getCenter());
$whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) '); $whereClause = sprintf(' {activity.person_id} = ? AND {activity.scope_id} IN ({scopes_ids}) ');
$scopes_ids = []; $scopes_ids = [];

View File

@ -1,4 +1,7 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.activity.timeline: chill.activity.timeline:
class: Chill\ActivityBundle\Timeline\TimelineActivityProvider class: Chill\ActivityBundle\Timeline\TimelineActivityProvider
@ -13,17 +16,14 @@ services:
- { name: chill.timeline, context: 'center' } - { name: chill.timeline, context: 'center' }
Chill\ActivityBundle\Menu\: Chill\ActivityBundle\Menu\:
autowire: true
autoconfigure: true
resource: '../Menu/' resource: '../Menu/'
tags: ['chill.menu_builder'] tags: ['chill.menu_builder']
Chill\ActivityBundle\Notification\: Chill\ActivityBundle\Notification\:
autowire: true
autoconfigure: true
resource: '../Notification' resource: '../Notification'
Chill\ActivityBundle\Security\Authorization\: Chill\ActivityBundle\Security\Authorization\:
resource: '../Security/Authorization/' resource: '../Security/Authorization/'
autowire: true
autoconfigure: true Chill\ActivityBundle\Repository\:
resource: '../Repository/'

View File

@ -1,82 +1,56 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.activity.export.count_activity: chill.activity.export.count_activity:
class: Chill\ActivityBundle\Export\Export\CountActivity class: Chill\ActivityBundle\Export\Export\CountActivity
arguments:
- "@doctrine.orm.entity_manager"
tags: tags:
- { name: chill.export, alias: 'count_activity' } - { name: chill.export, alias: 'count_activity' }
chill.activity.export.sum_activity_duration: chill.activity.export.sum_activity_duration:
class: Chill\ActivityBundle\Export\Export\StatActivityDuration class: Chill\ActivityBundle\Export\Export\StatActivityDuration
arguments:
- "@doctrine.orm.entity_manager"
- "sum"
tags: tags:
- { name: chill.export, alias: 'sum_activity_duration' } - { name: chill.export, alias: 'sum_activity_duration' }
chill.activity.export.list_activity: chill.activity.export.list_activity:
class: Chill\ActivityBundle\Export\Export\ListActivity class: Chill\ActivityBundle\Export\Export\ListActivity
arguments:
- "@doctrine.orm.entity_manager"
- "@translator"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export, alias: 'list_activity' } - { name: chill.export, alias: 'list_activity' }
chill.activity.export.reason_filter: chill.activity.export.reason_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter class: Chill\ActivityBundle\Export\Filter\ActivityReasonFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.reason"
tags: tags:
- { name: chill.export_filter, alias: 'activity_reason_filter' } - { name: chill.export_filter, alias: 'activity_reason_filter' }
chill.activity.export.type_filter: chill.activity.export.type_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter class: Chill\ActivityBundle\Export\Filter\ActivityTypeFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.activity_type"
tags: tags:
- { name: chill.export_filter, alias: 'activity_type_filter' } - { name: chill.export_filter, alias: 'activity_type_filter' }
chill.activity.export.date_filter: chill.activity.export.date_filter:
class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter class: Chill\ActivityBundle\Export\Filter\ActivityDateFilter
arguments:
- "@translator"
tags: tags:
- { name: chill.export_filter, alias: 'activity_date_filter' } - { name: chill.export_filter, alias: 'activity_date_filter' }
chill.activity.export.person_having_an_activity_between_date_filter: chill.activity.export.person_having_an_activity_between_date_filter:
class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter class: Chill\ActivityBundle\Export\Filter\PersonHavingActivityBetweenDateFilter
arguments:
- "@chill.main.helper.translatable_string"
- "@chill_activity.repository.reason"
- "@translator"
tags: tags:
- #0 register as a filter - #0 register as a filter
name: chill.export_filter name: chill.export_filter
alias: 'activity_person_having_ac_bw_date_filter' alias: 'activity_person_having_ac_bw_date_filter'
chill.activity.export.reason_aggregator: chill.activity.export.reason_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator
arguments:
- "@chill_activity.repository.reason_category"
- "@chill_activity.repository.reason"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export_aggregator, alias: activity_reason_aggregator } - { name: chill.export_aggregator, alias: activity_reason_aggregator }
chill.activity.export.type_aggregator: chill.activity.export.type_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityTypeAggregator
arguments:
- "@chill_activity.repository.activity_type"
- "@chill.main.helper.translatable_string"
tags: tags:
- { name: chill.export_aggregator, alias: activity_type_aggregator } - { name: chill.export_aggregator, alias: activity_type_aggregator }
chill.activity.export.user_aggregator: chill.activity.export.user_aggregator:
class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator class: Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator
arguments:
$em: "@doctrine.orm.entity_manager"
tags: tags:
- { name: chill.export_aggregator, alias: activity_user_aggregator } - { name: chill.export_aggregator, alias: activity_user_aggregator }

View File

@ -1,28 +1,12 @@
--- ---
services: services:
chill_activity.repository.activity_type: chill_activity.repository.activity_type: '@Chill\ActivityBundle\Repository\ActivityTypeRepository'
class: Doctrine\ORM\EntityRepository chill_activity.repository.reason: '@Chill\ActivityBundle\Repository\ActivityReasonRepository'
factory: ['@doctrine.orm.entity_manager', getRepository] chill_activity.repository.reason_category: '@Chill\ActivityBundle\Repository\ActivityReasonCategoryRepository'
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'
# 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: Chill\ActivityBundle\Repository\ActivityACLAwareRepository:
autowire: true autowire: true
autoconfigure: true autoconfigure: true

View File

@ -44,7 +44,7 @@ class AsideActivityCategory
* @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children") * @ORM\ManyToOne(targetEntity=AsideActivityCategory::class, inversedBy="children")
* @ORM\JoinColumn(nullable=true) * @ORM\JoinColumn(nullable=true)
*/ */
private AsideActivityCategory $parent; private ?AsideActivityCategory $parent = null;
/** /**
* @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent") * @ORM\OneToMany(targetEntity=AsideActivityCategory::class, mappedBy="parent")

View File

@ -1,42 +1,34 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form; namespace Chill\AMLI\BudgetBundle\Form;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository; use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\AMLI\BudgetBundle\Entity\Charge; use Chill\AMLI\BudgetBundle\Entity\Charge;
class ChargeType extends AbstractType class ChargeType extends AbstractType
{ {
/** protected ConfigRepository $configRepository;
*
* @var ConfigRepository protected TranslatableStringHelperInterface $translatableStringHelper;
*/
protected $configRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
ConfigRepository $configRepository, ConfigRepository $configRepository,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->configRepository = $configRepository; $this->configRepository = $configRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
@ -45,24 +37,23 @@ class ChargeType extends AbstractType
'placeholder' => 'Choose a charge type' 'placeholder' => 'Choose a charge type'
]) ])
->add('amount', MoneyType::class) ->add('amount', MoneyType::class)
->add('comment', TextAreaType::class, [ ->add('comment', TextareaType::class, [
'required' => false 'required' => false
]) ]);
;
if ($options['show_start_date']) { if ($options['show_start_date']) {
$builder->add('startDate', ChillDateType::class, [ $builder->add('startDate', ChillDateType::class, [
'label' => 'Start of validity period' 'label' => 'Start of validity period'
]); ]);
} }
if ($options['show_end_date']) { if ($options['show_end_date']) {
$builder->add('endDate', ChillDateType::class, [ $builder->add('endDate', ChillDateType::class, [
'required' => false, 'required' => false,
'label' => 'End of validity period' 'label' => 'End of validity period'
]); ]);
} }
if ($options['show_help']) { if ($options['show_help']) {
$builder->add('help', ChoiceType::class, [ $builder->add('help', ChoiceType::class, [
'choices' => [ 'choices' => [
@ -77,48 +68,39 @@ class ChargeType extends AbstractType
]); ]);
} }
} }
private function getTypes() private function getTypes()
{ {
$charges = $this->configRepository $charges = $this->configRepository
->getChargesLabels(); ->getChargesLabels();
// rewrite labels to filter in language // rewrite labels to filter in language
foreach ($charges as $key => $labels) { foreach ($charges as $key => $labels) {
$charges[$key] = $this->translatableStringHelper->localize($labels); $charges[$key] = $this->translatableStringHelper->localize($labels);
} }
\asort($charges); \asort($charges);
return \array_flip($charges); return \array_flip($charges);
} }
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults(array(
'data_class' => 'Chill\AMLI\BudgetBundle\Entity\Charge', 'data_class' => Charge::class,
'show_start_date' => true, 'show_start_date' => true,
'show_end_date' => true, 'show_end_date' => true,
'show_help' => true 'show_help' => true
)); ));
$resolver $resolver
->setAllowedTypes('show_start_date', 'boolean') ->setAllowedTypes('show_start_date', 'boolean')
->setAllowedTypes('show_end_date', 'boolean') ->setAllowedTypes('show_end_date', 'boolean')
->setAllowedTypes('show_help', 'boolean') ->setAllowedTypes('show_help', 'boolean');
;
} }
/**
* {@inheritdoc}
*/
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'chill_amli_budgetbundle_charge'; return 'chill_amli_budgetbundle_charge';
} }
} }

View File

@ -1,7 +1,10 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\BudgetBundle\Form; namespace Chill\AMLI\BudgetBundle\Form;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
@ -10,32 +13,22 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\AMLI\BudgetBundle\Config\ConfigRepository; use Chill\AMLI\BudgetBundle\Config\ConfigRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
class ResourceType extends AbstractType class ResourceType extends AbstractType
{ {
/** protected ConfigRepository $configRepository;
*
* @var ConfigRepository protected TranslatableStringHelperInterface $translatableStringHelper;
*/
protected $configRepository;
/**
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct( public function __construct(
ConfigRepository $configRepository, ConfigRepository $configRepository,
TranslatableStringHelper $translatableStringHelper TranslatableStringHelperInterface $translatableStringHelper
) { ) {
$this->configRepository = $configRepository; $this->configRepository = $configRepository;
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
@ -45,17 +38,16 @@ class ResourceType extends AbstractType
'label' => 'Resource element type' 'label' => 'Resource element type'
]) ])
->add('amount', MoneyType::class) ->add('amount', MoneyType::class)
->add('comment', TextAreaType::class, [ ->add('comment', TextareaType::class, [
'required' => false 'required' => false
]) ]);
;
if ($options['show_start_date']) { if ($options['show_start_date']) {
$builder->add('startDate', ChillDateType::class, [ $builder->add('startDate', ChillDateType::class, [
'label' => 'Start of validity period' 'label' => 'Start of validity period'
]); ]);
} }
if ($options['show_end_date']) { if ($options['show_end_date']) {
$builder->add('endDate', ChillDateType::class, [ $builder->add('endDate', ChillDateType::class, [
'required' => false, '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) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver->setDefaults(array( $resolver->setDefaults(array(
@ -89,20 +63,29 @@ class ResourceType extends AbstractType
'show_start_date' => true, 'show_start_date' => true,
'show_end_date' => true 'show_end_date' => true
)); ));
$resolver $resolver
->setAllowedTypes('show_start_date', 'boolean') ->setAllowedTypes('show_start_date', 'boolean')
->setAllowedTypes('show_end_date', 'boolean') ->setAllowedTypes('show_end_date', 'boolean');
;
} }
/**
* {@inheritdoc}
*/
public function getBlockPrefix() public function getBlockPrefix()
{ {
return 'chill_amli_budgetbundle_resource'; 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);
}
} }

View File

@ -1,38 +1,46 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\FamilyMembersBundle\Controller; namespace Chill\AMLI\FamilyMembersBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Chill\AMLI\FamilyMembersBundle\Repository\FamilyMemberRepository;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember; use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember;
use Chill\AMLI\FamilyMembersBundle\Security\Voter\FamilyMemberVoter; use Chill\AMLI\FamilyMembersBundle\Security\Voter\FamilyMemberVoter;
use Chill\AMLI\FamilyMembersBundle\Form\FamilyMemberType; use Chill\AMLI\FamilyMembersBundle\Form\FamilyMemberType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\TranslatorInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
class FamilyMemberController extends Controller class FamilyMemberController extends AbstractController
{ {
protected EntityManagerInterface $em; private EntityManagerInterface $em;
protected TranslatorInterface $translator; protected TranslatorInterface $translator;
protected LoggerInterface $chillMainLogger; protected LoggerInterface $chillMainLogger;
private FamilyMemberRepository $familyMemberRepository;
public function __construct( public function __construct(
EntityManagerInterface $em, EntityManagerInterface $entityManager,
TranslatorInterface $translator, TranslatorInterface $translator,
LoggerInterface $chillMainLogger LoggerInterface $chillMainLogger,
FamilyMemberRepository $familyMemberRepository
) { ) {
$this->em = $em; $this->em = $entityManager;
$this->translator = $translator; $this->translator = $translator;
$this->chillMainLogger = $chillMainLogger; $this->chillMainLogger = $chillMainLogger;
$this->familyMemberRepository = $familyMemberRepository;
} }
/** /**
* @Route( * @Route(
* "{_locale}/family-members/family-members/by-person/{id}", * "{_locale}/family-members/family-members/by-person/{id}",
@ -43,14 +51,12 @@ class FamilyMemberController extends Controller
{ {
$this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person); $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person);
$familyMembers = $this->em $familyMembers = $this->familyMemberRepository->findByPerson($person);
->getRepository(FamilyMember::class)
->findByPerson($person);
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', [
'person' => $person, 'person' => $person,
'familyMembers' => $familyMembers 'familyMembers' => $familyMembers
)); ]);
} }
/** /**
@ -61,9 +67,7 @@ class FamilyMemberController extends Controller
*/ */
public function newAction(Person $person, Request $request) public function newAction(Person $person, Request $request)
{ {
$familyMember = (new FamilyMember()) $familyMember = (new FamilyMember())->setPerson($person);
->setPerson($person)
;
$this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember); $this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember);
@ -72,10 +76,9 @@ class FamilyMemberController extends Controller
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager(); $this->em->persist($familyMember);
$em->persist($familyMember); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator->trans('Family member created')); $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(), 'form' => $form->createView(),
'person' => $person 'person' => $person
)); ]);
} }
/** /**
@ -105,9 +108,8 @@ class FamilyMemberController extends Controller
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() and $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager(); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator->trans('Family member updated')); $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, 'familyMember' => $familyMember,
'form' => $form->createView(), 'form' => $form->createView(),
'person' => $familyMember->getPerson() 'person' => $familyMember->getPerson()
)); ]);
} }
/** /**
@ -129,47 +131,42 @@ class FamilyMemberController extends Controller
* "{_locale}/family-members/family-members/{id}/delete", * "{_locale}/family-members/family-members/{id}/delete",
* name="chill_family_members_family_members_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 ' $this->denyAccessUnlessGranted(FamilyMemberVoter::DELETE, $familyMember, 'You are not '
. 'allowed to delete this family membership'); . 'allowed to delete this family membership');
$form = $this->createDeleteForm($id); $form = $this->createDeleteForm();
if ($request->getMethod() === Request::METHOD_DELETE) { if ($request->getMethod() === Request::METHOD_DELETE) {
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isValid()) { 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(), 'by_user' => $this->getUser()->getUsername(),
'family_member_id' => $familyMember->getId(), 'family_member_id' => $familyMember->getId(),
'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(), 'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(),
'link' => $familyMember->getLink() 'link' => $familyMember->getLink()
)); ]);
$em = $this->getDoctrine()->getManager(); $this->em->remove($familyMember);
$em->remove($familyMember); $this->em->flush();
$em->flush();
$this->addFlash('success', $this->translator $this->addFlash('success', $this->translator
->trans("The family member has been successfully removed.")); ->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() '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, 'familyMember' => $familyMember,
'delete_form' => $form->createView() 'delete_form' => $form->createView()
)); ]);
} }
/** /**
@ -182,23 +179,20 @@ class FamilyMemberController extends Controller
{ {
$this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember); $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember);
return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', array( return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', [
'familyMember' => $familyMember 'familyMember' => $familyMember
)); ]);
} }
/** /**
* Creates a form to delete a help request entity by id. * 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) ->setMethod(Request::METHOD_DELETE)
->add('submit', SubmitType::class, array('label' => 'Delete')) ->add('submit', SubmitType::class, ['label' => 'Delete'])
->getForm() ->getForm()
; ;
} }

View File

@ -1,17 +1,32 @@
<?php <?php
declare(strict_types=1);
namespace Chill\AMLI\FamilyMembersBundle\Repository; namespace Chill\AMLI\FamilyMembersBundle\Repository;
use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/** /**
* FamilyMemberRepository * @method FamilyMember|null find($id, $lockMode = null, $lockVersion = null)
* * @method FamilyMember|null findOneBy(array $criteria, array $orderBy = null)
* @method FamilyMember[] findAll()
* @method FamilyMember[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/ */
class FamilyMemberRepository extends \Doctrine\ORM\EntityRepository class FamilyMemberRepository extends ServiceEntityRepository
{ {
public function findActiveByPerson(Person $person) public function __construct(ManagerRegistry $registry)
{ {
return $this->findBy([ 'person' => $person ]); parent::__construct($registry, FamilyMember::class);
}
/**
* @return FamilyMember[]
*/
public function findByPerson(Person $person): array
{
return $this->findBy(['person' => $person]);
} }
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Entity; namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
@ -18,12 +20,12 @@ class RoleScope
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private int $id; private ?int $id = null;
/** /**
* @ORM\Column(type="string", length=255) * @ORM\Column(type="string", length=255)
*/ */
private string $role; private ?string $role = null;
/** /**
* @ORM\ManyToOne( * @ORM\ManyToOne(
@ -32,7 +34,7 @@ class RoleScope
* @ORM\JoinColumn(nullable=true, name="scope_id") * @ORM\JoinColumn(nullable=true, name="scope_id")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE") * @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/ */
private Scope $scope; private ?Scope $scope = null;
/** /**
* @var Collection * @var Collection
@ -43,53 +45,33 @@ class RoleScope
*/ */
private $permissionsGroups; private $permissionsGroups;
private bool $new;
public function __construct() { public function __construct() {
$this->new = true;
$this->permissionsGroups = new ArrayCollection(); $this->permissionsGroups = new ArrayCollection();
} }
/** public function getId(): ?int
* @return int
*/
public function getId()
{ {
return $this->id; return $this->id;
} }
/** public function getRole(): ?string
* @return string
*/
public function getRole()
{ {
return $this->role; return $this->role;
} }
/** public function getScope(): ?Scope
* @return Scope
*/
public function getScope()
{ {
return $this->scope; return $this->scope;
} }
/** public function setRole(?string $role = null): self
* @param type $role
* @return RoleScope
*/
public function setRole($role)
{ {
$this->role = $role; $this->role = $role;
return $this; return $this;
} }
/** public function setScope(?Scope $scope = null): self
* @param Scope $scope
* @return RoleScope
*/
public function setScope(Scope $scope = null)
{ {
$this->scope = $scope; $this->scope = $scope;

View File

@ -1,48 +1,24 @@
<?php <?php
/*
* Copyright (C) 2018 Julien Fastré <julien.fastre@champs-libres.coop> declare(strict_types=1);
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Security\Authorization; namespace Chill\MainBundle\Security\Authorization;
use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Role\Role;
/**
*
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*/
class ChillExportVoter extends Voter class ChillExportVoter extends Voter
{ {
const EXPORT = 'chill_export'; public const EXPORT = 'chill_export';
/** protected AuthorizationHelperInterface $authorizationHelper;
*
* @var AuthorizationHelper public function __construct(AuthorizationHelperInterface $authorizationHelper)
*/
protected $authorizationHelper;
public function __construct(AuthorizationHelper $authorizationHelper)
{ {
$this->authorizationHelper = $authorizationHelper; $this->authorizationHelper = $authorizationHelper;
} }
protected function supports($attribute, $subject): bool protected function supports($attribute, $subject): bool
{ {
return $attribute === self::EXPORT; return $attribute === self::EXPORT;
@ -53,10 +29,7 @@ class ChillExportVoter extends Voter
if (!$token->getUser() instanceof User) { if (!$token->getUser() instanceof User) {
return false; return false;
} }
$centers = $this->authorizationHelper return [] !== $this->authorizationHelper->getReachableCenters($token->getUser(), $attribute);
->getReachableCenters($token->getUser(), new Role($attribute));
return count($centers) > 0;
} }
} }

View File

@ -1,27 +1,43 @@
<?php <?php
declare(strict_types=1);
namespace Chill\MainBundle\Security\Resolver; namespace Chill\MainBundle\Security\Resolver;
class CenterResolverDispatcher use Chill\MainBundle\Entity\Center;
/**
* @deprecated Use CenterResolverManager and its interface CenterResolverManagerInterface
*/
final class CenterResolverDispatcher
{ {
/** /**
* @var iterabble|CenterResolverInterface[] * @var CenterResolverInterface[]
*/ */
private iterable $resolvers = []; private iterable $resolvers;
public function __construct(iterable $resolvers) public function __construct(iterable $resolvers = [])
{ {
$this->resolvers = $resolvers; $this->resolvers = $resolvers;
} }
/** /**
* @param mixed $entity * @param object $entity
* @param array|null $options
* @return null|Center|Center[] * @return null|Center|Center[]
*/ */
public function resolveCenter($entity, ?array $options = []) 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)) { if ($resolver->supports($entity, $options)) {
return $resolver->resolveCenter($entity, $options); return $resolver->resolveCenter($entity, $options);
} }

View File

@ -6,12 +6,14 @@ use Chill\MainBundle\Entity\Center;
interface CenterResolverInterface interface CenterResolverInterface
{ {
/**
* @param object $entity
*/
public function supports($entity, ?array $options = []): bool; public function supports($entity, ?array $options = []): bool;
/** /**
* @param $entity * @param object $entity
* @param array|null $options * @return Center|Center[]
* @return Center|array|Center[]
*/ */
public function resolveCenter($entity, ?array $options = []); public function resolveCenter($entity, ?array $options = []);

View File

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace Chill\MainBundle\Security\Resolver;
final class CenterResolverManager implements CenterResolverManagerInterface
{
/**
* @var CenterResolverInterface[]
*/
private iterable $resolvers;
public function __construct(iterable $resolvers = [])
{
$this->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 [];
}
}

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Chill\MainBundle\Security\Resolver;
use Chill\MainBundle\Entity\Center;
interface CenterResolverManagerInterface
{
/**
* @param object $entity
* @return Center[]
*/
public function resolveCenters($entity, ?array $options = []): array;
}

View File

@ -1,92 +1,56 @@
<?php <?php
/*
* Chill is a suite of a modules, Chill is a software for social workers declare(strict_types=1);
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\MainBundle\Templating; namespace Chill\MainBundle\Templating;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Translation\Translator; use Symfony\Contracts\Translation\TranslatorInterface;
/** final class TranslatableStringHelper implements TranslatableStringHelperInterface
*
* This helper helps to find the string in current locale from translatable_strings
*
* @author Julien Fastré <julien.fastre@champs-libres.coop>
*
*/
class TranslatableStringHelper
{ {
/** private RequestStack $requestStack;
*
* @var RequestStack private TranslatorInterface $translator;
*/
private $requestStack; public function __construct(RequestStack $requestStack, TranslatorInterface $translator)
private $fallbackLocales;
public function __construct(RequestStack $requestStack, Translator $translator)
{ {
$this->requestStack = $requestStack; $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])) { public function localize(array $translatableStrings): ?string
{
return $translatableStrings[$language]; if ([] === $translatableStrings) {
} else { return null;
foreach ($this->fallbackLocales as $locale) {
if (array_key_exists($locale, $translatableStrings)) {
return $translatableStrings[$locale];
}
}
} }
$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 // no fallback translation... trying the first available
$langs = array_keys($translatableStrings); $langs = array_keys($translatableStrings);
if (count($langs) === 0) { if ([] === $langs) {
return ''; return '';
} }
return $translatableStrings[$langs[0]];
return $translatableStrings[$langs[0]];
} }
} }

View File

@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace Chill\MainBundle\Templating;
interface TranslatableStringHelperInterface
{
/**
* 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.
*/
public function localize(array $translatableStrings): ?string;
}

View File

@ -8,38 +8,29 @@ services:
Chill\MainBundle\Repository\: Chill\MainBundle\Repository\:
resource: '../Repository/' resource: '../Repository/'
autowire: true
autoconfigure: true
Chill\MainBundle\Repository\UserACLAwareRepositoryInterface: '@Chill\MainBundle\Repository\UserACLAwareRepository' Chill\MainBundle\Repository\UserACLAwareRepositoryInterface: '@Chill\MainBundle\Repository\UserACLAwareRepository'
Chill\MainBundle\Serializer\Normalizer\: Chill\MainBundle\Serializer\Normalizer\:
resource: '../Serializer/Normalizer' resource: '../Serializer/Normalizer'
autoconfigure: true
autowire: true
tags: tags:
- { name: 'serializer.normalizer', priority: 64 } - { name: 'serializer.normalizer', priority: 64 }
Chill\MainBundle\Form\Type\: Chill\MainBundle\Form\Type\:
resource: '../Form/Type' resource: '../Form/Type'
autoconfigure: true
autowire: true
tags: tags:
- { name: form.type } - { name: form.type }
Chill\MainBundle\Doctrine\Event\: Chill\MainBundle\Doctrine\Event\:
resource: '../Doctrine/Event/' resource: '../Doctrine/Event/'
autowire: true
tags: tags:
- { name: 'doctrine.event_subscriber' } - { name: 'doctrine.event_subscriber' }
chill.main.helper.translatable_string: chill.main.helper.translatable_string:
class: Chill\MainBundle\Templating\TranslatableStringHelper class: Chill\MainBundle\Templating\TranslatableStringHelper
arguments:
- "@request_stack"
- "@translator.default"
Chill\MainBundle\Templating\TranslatableStringHelper: '@chill.main.helper.translatable_string' Chill\MainBundle\Templating\TranslatableStringHelper: '@chill.main.helper.translatable_string'
Chill\MainBundle\Templating\TranslatableStringHelperInterface: '@Chill\MainBundle\Templating\TranslatableStringHelper'
chill.main.twig.translatable_string: chill.main.twig.translatable_string:
class: Chill\MainBundle\Templating\TranslatableStringTwig class: Chill\MainBundle\Templating\TranslatableStringTwig

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill_main.tag_aware_cache: chill_main.tag_aware_cache:
class: Symfony\Component\Cache\Adapter\TagAwareAdapter class: Symfony\Component\Cache\Adapter\TagAwareAdapter
arguments: arguments:

View File

@ -1,11 +1,9 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Command\ChillImportUsersCommand: Chill\MainBundle\Command\ChillImportUsersCommand:
arguments:
$em: '@Doctrine\ORM\EntityManagerInterface'
$logger: '@Psr\Log\LoggerInterface'
$passwordEncoder: '@Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface'
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
$userRepository: '@Chill\MainBundle\Repository\UserRepository'
tags: tags:
- { name: console.command } - { name: console.command }

View File

@ -1,12 +1,13 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Controller\: Chill\MainBundle\Controller\:
autowire: true
resource: '../../Controller' resource: '../../Controller'
tags: ['controller.service_arguments'] tags: ['controller.service_arguments']
Chill\MainBundle\Controller\PasswordController: Chill\MainBundle\Controller\PasswordController:
autowire: true
arguments: arguments:
$chillLogger: '@monolog.logger.chill' $chillLogger: '@monolog.logger.chill'
tags: ['controller.service_arguments'] tags: ['controller.service_arguments']
@ -28,10 +29,6 @@ services:
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments'] tags: ['controller.service_arguments']
Chill\MainBundle\Controller\UserController:
autowire: true
autoconfigure: true
Chill\MainBundle\Controller\NotificationController: Chill\MainBundle\Controller\NotificationController:
arguments: arguments:
$security: '@Symfony\Component\Security\Core\Security' $security: '@Symfony\Component\Security\Core\Security'

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader: Chill\MainBundle\CRUD\Routing\CRUDRoutesLoader:
arguments: arguments:
$crudConfig: '%chill_main_crud_route_loader_config%' $crudConfig: '%chill_main_crud_route_loader_config%'

View File

@ -1,3 +1,7 @@
--- ---
services: services:
'Chill\MainBundle\Doctrine\Migrations\VersionComparator': ~ _defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Doctrine\Migrations\VersionComparator: ~

View File

@ -1,9 +1,13 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.main.export_element_validator: chill.main.export_element_validator:
class: Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraintValidator class: Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraintValidator
tags: tags:
- { name: validator.constraint_validator } - { name: validator.constraint_validator }
# deprecated in favor of spreadsheet_formatter # deprecated in favor of spreadsheet_formatter
# chill.main.export.csv_formatter: # chill.main.export.csv_formatter:
# class: Chill\MainBundle\Export\Formatter\CSVFormatter # class: Chill\MainBundle\Export\Formatter\CSVFormatter
@ -11,7 +15,7 @@ services:
# - "@translator" # - "@translator"
# tags: # tags:
# - { name: chill.export_formatter, alias: 'csv' } # - { name: chill.export_formatter, alias: 'csv' }
chill.main.export.spreadsheet_formatter: chill.main.export.spreadsheet_formatter:
class: Chill\MainBundle\Export\Formatter\SpreadSheetFormatter class: Chill\MainBundle\Export\Formatter\SpreadSheetFormatter
arguments: arguments:
@ -19,7 +23,7 @@ services:
$exportManager: '@Chill\MainBundle\Export\ExportManager' $exportManager: '@Chill\MainBundle\Export\ExportManager'
tags: tags:
- { name: chill.export_formatter, alias: 'spreadsheet' } - { name: chill.export_formatter, alias: 'spreadsheet' }
chill.main.export.list_formatter: chill.main.export.list_formatter:
class: Chill\MainBundle\Export\Formatter\CSVListFormatter class: Chill\MainBundle\Export\Formatter\CSVListFormatter
arguments: arguments:
@ -27,7 +31,7 @@ services:
$exportManager: '@Chill\MainBundle\Export\ExportManager' $exportManager: '@Chill\MainBundle\Export\ExportManager'
tags: tags:
- { name: chill.export_formatter, alias: 'csvlist' } - { name: chill.export_formatter, alias: 'csvlist' }
chill.main.export.list_spreadsheet_formatter: chill.main.export.list_spreadsheet_formatter:
class: Chill\MainBundle\Export\Formatter\SpreadsheetListFormatter class: Chill\MainBundle\Export\Formatter\SpreadsheetListFormatter
arguments: arguments:
@ -35,7 +39,7 @@ services:
$exportManager: '@Chill\MainBundle\Export\ExportManager' $exportManager: '@Chill\MainBundle\Export\ExportManager'
tags: tags:
- { name: chill.export_formatter, alias: 'spreadlist' } - { name: chill.export_formatter, alias: 'spreadlist' }
chill.main.export.pivoted_list_formatter: chill.main.export.pivoted_list_formatter:
class: Chill\MainBundle\Export\Formatter\CSVPivotedListFormatter class: Chill\MainBundle\Export\Formatter\CSVPivotedListFormatter
arguments: arguments:
@ -43,4 +47,3 @@ services:
$exportManager: '@Chill\MainBundle\Export\ExportManager' $exportManager: '@Chill\MainBundle\Export\ExportManager'
tags: tags:
- { name: chill.export_formatter, alias: 'csv_pivoted_list' } - { name: chill.export_formatter, alias: 'csv_pivoted_list' }

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\DataFixtures\ORM\: Chill\MainBundle\DataFixtures\ORM\:
resource: ../../DataFixtures/ORM resource: ../../DataFixtures/ORM
tags: [ 'doctrine.fixture.orm' ] tags: [ 'doctrine.fixture.orm' ]

View File

@ -1,4 +1,7 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.main.form.type.translatable.string: chill.main.form.type.translatable.string:
class: Chill\MainBundle\Form\Type\TranslatableStringFormType class: Chill\MainBundle\Form\Type\TranslatableStringFormType
@ -39,9 +42,7 @@ services:
tags: tags:
- { name: form.type, alias: select2_chill_language } - { name: form.type, alias: select2_chill_language }
Chill\MainBundle\Form\Type\PickCenterType: Chill\MainBundle\Form\Type\PickCenterType: ~
autowire: true
autoconfigure: true
chill.main.form.type.composed_role_scope: chill.main.form.type.composed_role_scope:
class: Chill\MainBundle\Form\Type\ComposedRoleScopeType class: Chill\MainBundle\Form\Type\ComposedRoleScopeType
@ -62,9 +63,7 @@ services:
tags: tags:
- { name: form.type } - { name: form.type }
Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader: Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader: ~
autowire: true
autoconfigure: true
chill.main.form.type.export: chill.main.form.type.export:
class: Chill\MainBundle\Form\Type\Export\ExportType class: Chill\MainBundle\Form\Type\Export\ExportType
@ -96,14 +95,10 @@ services:
arguments: arguments:
- '@Chill\MainBundle\Export\ExportManager' - '@Chill\MainBundle\Export\ExportManager'
Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer: Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer: ~
autowire: true
autoconfigure: true
chill.main.form.advanced_search_type: chill.main.form.advanced_search_type:
class: Chill\MainBundle\Form\AdvancedSearchType class: Chill\MainBundle\Form\AdvancedSearchType
autowire: true
autoconfigure: true
arguments: arguments:
- "@chill_main.search_provider" - "@chill_main.search_provider"
tags: tags:
@ -116,9 +111,7 @@ services:
tags: tags:
- { name: form.type } - { name: form.type }
Chill\MainBundle\Form\UserType: Chill\MainBundle\Form\UserType: ~
autowire: true
autoconfigure: true
Chill\MainBundle\Form\PermissionsGroupType: Chill\MainBundle\Form\PermissionsGroupType:
tags: tags:
@ -131,15 +124,8 @@ services:
tags: tags:
- { name: form.type } - { name: form.type }
Chill\MainBundle\Form\Type\PickAddressType: ~
Chill\MainBundle\Form\Type\PickAddressType: Chill\MainBundle\Form\DataTransform\AddressToIdDataTransformer: ~
autoconfigure: true
autowire: true
Chill\MainBundle\Form\DataTransform\AddressToIdDataTransformer: Chill\MainBundle\Form\Type\LocationFormType: ~
autoconfigure: true
autowire: true
Chill\MainBundle\Form\Type\LocationFormType:
autowire: true
autoconfigure: true

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.main.logger: chill.main.logger:
# a logger to log events from the app (deletion, remove, etc.) # a logger to log events from the app (deletion, remove, etc.)
alias: monolog.logger.chill alias: monolog.logger.chill

View File

@ -1,9 +1,11 @@
services: services:
Chill\MainBundle\Routing\MenuBuilder\: _defaults:
resource: '../../Routing/MenuBuilder'
autowire: true autowire: true
autoconfigure: true autoconfigure: true
Chill\MainBundle\Routing\MenuBuilder\:
resource: '../../Routing/MenuBuilder'
Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder: Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder:
arguments: arguments:
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Notification\Mailer: Chill\MainBundle\Notification\Mailer:
arguments: arguments:
$logger: '@Psr\Log\LoggerInterface' $logger: '@Psr\Log\LoggerInterface'
@ -9,6 +13,4 @@ services:
$translator: '@Symfony\Component\Translation\TranslatorInterface' $translator: '@Symfony\Component\Translation\TranslatorInterface'
$routeParameters: '%chill_main.notifications%' $routeParameters: '%chill_main.notifications%'
Chill\MainBundle\Notification\NotificationRenderer: Chill\MainBundle\Notification\NotificationRenderer: ~
autoconfigure: true
autowire: true

View File

@ -1,9 +1,11 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill_main.paginator_factory: chill_main.paginator_factory:
class: Chill\MainBundle\Pagination\PaginatorFactory class: Chill\MainBundle\Pagination\PaginatorFactory
public: true public: true
autowire: true
autoconfigure: true
arguments: arguments:
- "@request_stack" - "@request_stack"
- "@router" - "@router"

View File

@ -1,19 +1,21 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Phonenumber\PhonenumberHelper: Chill\MainBundle\Phonenumber\PhonenumberHelper:
arguments: arguments:
$logger: '@Psr\Log\LoggerInterface'
$config: '%chill_main.phone_helper%' $config: '%chill_main.phone_helper%'
$cachePool: '@cache.user_data' $cachePool: '@cache.user_data'
Chill\MainBundle\Phonenumber\Templating: Chill\MainBundle\Phonenumber\Templating:
arguments: arguments:
$phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper' $phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper'
tags: tags:
- { name: twig.extension } - { name: twig.extension }
Chill\MainBundle\Validation\Validator\ValidPhonenumber: Chill\MainBundle\Validation\Validator\ValidPhonenumber:
arguments: arguments:
$logger: '@Psr\Log\LoggerInterface'
$phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper' $phonenumberHelper: '@Chill\MainBundle\Phonenumber\PhonenumberHelper'
tags: tags:
- { name: validator.constraint_validator } - { name: validator.constraint_validator }

View File

@ -1,10 +1,13 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Redis\RedisConnectionFactory: Chill\MainBundle\Redis\RedisConnectionFactory:
arguments: arguments:
$parameters: "%chill_main.redis%" $parameters: "%chill_main.redis%"
tags: tags:
- { name: kernel.event_subcriber } - { name: kernel.event_subcriber }
Chill\MainBundle\Redis\ChillRedis: Chill\MainBundle\Redis\ChillRedis:
factory: [ '@Chill\MainBundle\Redis\RedisConnectionFactory', 'create' ] factory: [ '@Chill\MainBundle\Redis\RedisConnectionFactory', 'create' ]

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill.main.menu_composer: chill.main.menu_composer:
class: Chill\MainBundle\Routing\MenuComposer class: Chill\MainBundle\Routing\MenuComposer
arguments: arguments:
@ -6,7 +10,7 @@ services:
- '@Knp\Menu\FactoryInterface' - '@Knp\Menu\FactoryInterface'
- '@Symfony\Component\Translation\TranslatorInterface' - '@Symfony\Component\Translation\TranslatorInterface'
Chill\MainBundle\Routing\MenuComposer: '@chill.main.menu_composer' Chill\MainBundle\Routing\MenuComposer: '@chill.main.menu_composer'
chill.main.routes_loader: chill.main.routes_loader:
class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader class: Chill\MainBundle\Routing\Loader\ChillRoutesLoader
arguments: arguments:

View File

@ -1,14 +1,14 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill_main.search_provider: chill_main.search_provider:
class: Chill\MainBundle\Search\SearchProvider class: Chill\MainBundle\Search\SearchProvider
Chill\MainBundle\Search\SearchProvider: '@chill_main.search_provider' Chill\MainBundle\Search\SearchProvider: '@chill_main.search_provider'
Chill\MainBundle\Search\SearchApi: Chill\MainBundle\Search\SearchApi: ~
autowire: true
autoconfigure: true
Chill\MainBundle\Search\Entity\: Chill\MainBundle\Search\Entity\:
autowire: true
autoconfigure: true
resource: '../../Search/Entity' resource: '../../Search/Entity'

View File

@ -3,46 +3,35 @@ services:
autowire: true autowire: true
autoconfigure: true autoconfigure: true
# do not autowire the directory Security/Resolver
Chill\MainBundle\Security\Resolver\CenterResolverDispatcher: Chill\MainBundle\Security\Resolver\CenterResolverDispatcher:
arguments: arguments:
- !tagged_iterator chill_main.center_resolver - !tagged_iterator chill_main.center_resolver
Chill\MainBundle\Security\Resolver\CenterResolverManager:
arguments:
- !tagged_iterator chill_main.center_resolver
Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface: '@Chill\MainBundle\Security\Resolver\CenterResolverManager'
Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher: Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher:
arguments: arguments:
- !tagged_iterator chill_main.scope_resolver - !tagged_iterator chill_main.scope_resolver
# do not autowire the directory Security/Resolver Chill\MainBundle\Security\Resolver\DefaultCenterResolver: ~
Chill\MainBundle\Security\Resolver\DefaultCenterResolver:
autoconfigure: true
autowire: true
Chill\MainBundle\Security\Resolver\DefaultScopeResolver: Chill\MainBundle\Security\Resolver\DefaultScopeResolver: ~
autoconfigure: true
autowire: true
# do not autowire the directory Security/Resolver Chill\MainBundle\Security\Resolver\ResolverTwigExtension: ~
Chill\MainBundle\Security\Resolver\ResolverTwigExtension:
autoconfigure: true
autowire: true
# do not autowire the directory Security/Resolver Chill\MainBundle\Security\Authorization\DefaultVoterHelperFactory: ~
Chill\MainBundle\Security\Authorization\DefaultVoterHelperFactory:
autowire: true
# do not autowire the directory Security/Resolver
Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface: '@Chill\MainBundle\Security\Authorization\DefaultVoterHelperFactory' Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface: '@Chill\MainBundle\Security\Authorization\DefaultVoterHelperFactory'
chill.main.security.authorization.helper: chill.main.security.authorization.helper:
class: Chill\MainBundle\Security\Authorization\AuthorizationHelper class: Chill\MainBundle\Security\Authorization\AuthorizationHelper
autowire: true
autoconfigure: true
Chill\MainBundle\Security\Authorization\AuthorizationHelper: '@chill.main.security.authorization.helper' Chill\MainBundle\Security\Authorization\AuthorizationHelper: '@chill.main.security.authorization.helper'
Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface: '@chill.main.security.authorization.helper' Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface: '@chill.main.security.authorization.helper'
Chill\MainBundle\Security\ParentRoleHelper: Chill\MainBundle\Security\ParentRoleHelper: ~
autowire: true
autoconfigure: true
chill.main.role_provider: chill.main.role_provider:
class: Chill\MainBundle\Security\RoleProvider class: Chill\MainBundle\Security\RoleProvider
@ -54,20 +43,16 @@ services:
Symfony\Component\Security\Core\User\UserProviderInterface: "@chill.main.user_provider" Symfony\Component\Security\Core\User\UserProviderInterface: "@chill.main.user_provider"
Chill\MainBundle\Security\Authorization\ChillExportVoter: Chill\MainBundle\Security\Authorization\ChillExportVoter:
arguments:
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
tags: tags:
- { name: security.voter } - { name: security.voter }
Chill\MainBundle\Security\PasswordRecover\TokenManager: Chill\MainBundle\Security\PasswordRecover\TokenManager:
arguments: arguments:
$secret: '%kernel.secret%' $secret: '%kernel.secret%'
$logger: '@Psr\Log\LoggerInterface'
Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper: Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper:
arguments: arguments:
$tokenManager: '@Chill\MainBundle\Security\PasswordRecover\TokenManager' $tokenManager: '@Chill\MainBundle\Security\PasswordRecover\TokenManager'
$urlGenerator: '@Symfony\Component\Routing\Generator\UrlGeneratorInterface'
$mailer: '@Chill\MainBundle\Notification\Mailer' $mailer: '@Chill\MainBundle\Notification\Mailer'
$routeParameters: "%chill_main.notifications%" $routeParameters: "%chill_main.notifications%"
@ -80,11 +65,9 @@ services:
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker: Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker:
arguments: arguments:
$chillRedis: '@Chill\MainBundle\Redis\ChillRedis' $chillRedis: '@Chill\MainBundle\Redis\ChillRedis'
$logger: '@Psr\Log\LoggerInterface'
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverVoter: Chill\MainBundle\Security\PasswordRecover\PasswordRecoverVoter:
arguments: arguments:
$locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker' $locker: '@Chill\MainBundle\Security\PasswordRecover\PasswordRecoverLocker'
$requestStack: '@Symfony\Component\HttpFoundation\RequestStack'
tags: tags:
- { name: security.voter } - { name: security.voter }

View File

@ -1,11 +1,13 @@
--- ---
services: services:
_defaults:
autowire: true
autoconfigure: true
# note: the autowiring for serializers and normalizers is declared # note: the autowiring for serializers and normalizers is declared
# into ../services.yaml # into ../services.yaml
Chill\MainBundle\Serializer\Normalizer\DoctrineExistingEntityNormalizer: Chill\MainBundle\Serializer\Normalizer\DoctrineExistingEntityNormalizer:
autowire: true
tags: tags:
- { name: 'serializer.normalizer', priority: 8 } - { name: 'serializer.normalizer', priority: 8 }

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
# twig_intl: # twig_intl:
# class: Twig_Extensions_Extension_Intl # class: Twig_Extensions_Extension_Intl
# tags: # tags:
@ -32,8 +36,6 @@ services:
- { name: twig.extension } - { name: twig.extension }
Chill\MainBundle\Templating\Entity\CommentRender: Chill\MainBundle\Templating\Entity\CommentRender:
autoconfigure: true
autowire: true
tags: tags:
- { name: 'chill.render_entity' } - { name: 'chill.render_entity' }
@ -41,17 +43,11 @@ services:
tags: tags:
- { name: twig.extension } - { name: twig.extension }
Chill\MainBundle\Templating\Entity\AddressRender: Chill\MainBundle\Templating\Entity\AddressRender: ~
autoconfigure: true
autowire: true
Chill\MainBundle\Templating\Entity\UserRender: Chill\MainBundle\Templating\Entity\UserRender: ~
autoconfigure: true
autowire: true
Chill\MainBundle\Templating\Listing\: Chill\MainBundle\Templating\Listing\:
resource: './../../Templating/Listing' resource: './../../Templating/Listing'
autoconfigure: true
autowire: true
Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface: '@Chill\MainBundle\Templating\Listing\FilterOrderHelperFactory' Chill\MainBundle\Templating\Listing\FilterOrderHelperFactoryInterface: '@Chill\MainBundle\Templating\Listing\FilterOrderHelperFactory'

View File

@ -1,4 +1,8 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill_main.timeline_builder: chill_main.timeline_builder:
class: Chill\MainBundle\Timeline\TimelineBuilder class: Chill\MainBundle\Timeline\TimelineBuilder
arguments: arguments:

View File

@ -1,11 +1,15 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
chill_main.validator_user_circle_consistency: chill_main.validator_user_circle_consistency:
class: Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistencyValidator class: Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistencyValidator
arguments: arguments:
- "@chill.main.security.authorization.helper" - "@chill.main.security.authorization.helper"
tags: tags:
- { name: "validator.constraint_validator" } - { name: "validator.constraint_validator" }
Chill\MainBundle\Validation\Validator\UserUniqueEmailAndUsername: Chill\MainBundle\Validation\Validator\UserUniqueEmailAndUsername:
arguments: arguments:
$em: '@Doctrine\ORM\EntityManagerInterface' $em: '@Doctrine\ORM\EntityManagerInterface'

View File

@ -1,2 +1,6 @@
services: services:
_defaults:
autowire: true
autoconfigure: true
Chill\MainBundle\Templating\UI\CountNotificationUser: ~ Chill\MainBundle\Templating\UI\CountNotificationUser: ~

View File

@ -63,7 +63,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* @ORM\Column(name="id", type="integer") * @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO") * @ORM\GeneratedValue(strategy="AUTO")
*/ */
private int $id; private ?int $id = null;
/** /**
* The person's first name * The person's first name
@ -305,11 +305,10 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/** /**
* The person's center * The person's center
* @var Center
* *
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center") * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center")
*/ */
private $center; private ?Center $center = null;
/** /**
* The person's accompanying periods (when the person was accompanied by the center) * The person's accompanying periods (when the person was accompanied by the center)
@ -713,7 +712,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return false; return false;
} }
public function getId(): int public function getId(): ?int
{ {
return $this->id; return $this->id;
} }

View File

@ -1,83 +1,49 @@
<?php <?php
/*
* declare(strict_types=1);
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
*
* 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 <http://www.gnu.org/licenses/>.
*/
namespace Chill\PersonBundle\Form\SocialWork; namespace Chill\PersonBundle\Form\SocialWork;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Chill\MainBundle\Form\Type\TranslatableStringFormType; use Chill\MainBundle\Form\Type\TranslatableStringFormType;
use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
/**
* Class SocialIssueType
*
* @package Chill\PersonBundle\Form
*/
class SocialIssueType extends AbstractType class SocialIssueType extends AbstractType
{ {
/** protected TranslatableStringHelperInterface $translatableStringHelper;
*
* @var TranslatableStringHelper
*/
protected $translatableStringHelper;
public function __construct(TranslatableStringHelper $translatableStringHelper) { public function __construct(
TranslatableStringHelperInterface $translatableStringHelper
) {
$this->translatableStringHelper = $translatableStringHelper; $this->translatableStringHelper = $translatableStringHelper;
} }
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('title', TranslatableStringFormType::class, [ ->add('title', TranslatableStringFormType::class, [
'label' => 'Nom' 'label' => 'Nom'
]) ])
->add('parent', EntityType::class, [ ->add('parent', EntityType::class, [
'class' => SocialIssue::class, 'class' => SocialIssue::class,
'required' => false, 'required' => false,
'choice_label' => function (SocialIssue $issue) { 'choice_label' => fn (SocialIssue $issue): ?string => $this->translatableStringHelper->localize($issue->getTitle())
return $this->translatableStringHelper->localize($issue->getTitle());
}
]) ])
->add('desactivationDate', DateType::class, [ ->add('desactivationDate', DateType::class, [
'attr' => ['class' => 'datepicker'], 'attr' => ['class' => 'datepicker'],
'widget'=> 'single_text', 'widget'=> 'single_text',
'format' => 'dd-MM-yyyy', 'format' => 'dd-MM-yyyy',
'required' => false, 'required' => false,
]); ]);
} }
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver) public function configureOptions(OptionsResolver $resolver)
{ {
$resolver $resolver->setDefault('class', SocialIssue::class);
->setDefault('class', SocialIssue::class)
;
} }
} }

View File

@ -1,14 +1,18 @@
<?php <?php
declare(strict_types=1);
namespace Validator\Person; namespace Validator\Person;
use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter; use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter;
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenterValidator; use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenterValidator;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
class PersonHasCenterValidatorTest extends \Symfony\Component\Validator\Test\ConstraintValidatorTestCase class PersonHasCenterValidatorTest extends ConstraintValidatorTestCase
{ {
public function testValidateRequired() public function testValidateRequired()
{ {
@ -42,9 +46,10 @@ class PersonHasCenterValidatorTest extends \Symfony\Component\Validator\Test\Con
'validation' => [ 'validation' => [
'center_required' => true 'center_required' => true
] ]
]) ]);
;
return new PersonHasCenterValidator($parameterBag); $centerResolverDispatcher = $this->createMock(CenterResolverDispatcher::class);
return new PersonHasCenterValidator($parameterBag, $centerResolverDispatcher);
} }
} }

View File

@ -22,7 +22,6 @@ use Chill\MainBundle\Timeline\TimelineSingleQuery;
*/ */
class TimelineReportProvider implements TimelineProviderInterface class TimelineReportProvider implements TimelineProviderInterface
{ {
protected EntityManager $em; protected EntityManager $em;
protected AuthorizationHelper $helper; protected AuthorizationHelper $helper;
@ -84,11 +83,12 @@ class TimelineReportProvider implements TimelineProviderInterface
private function getWhereClauseForCenter(string $context, array $args): array private function getWhereClauseForCenter(string $context, array $args): array
{ {
$role = 'CHILL_REPORT_SEE';
$report = $this->em->getClassMetadata(Report::class); $report = $this->em->getClassMetadata(Report::class);
$person = $this->em->getClassMetadata(Person::class); $person = $this->em->getClassMetadata(Person::class);
$role = new Role('CHILL_REPORT_SEE');
$reachableCenters = $this->helper->getReachableCenters($this->security->getUser(), $reachableCenters = $this->helper->getReachableCenters($this->security->getUser(), $role);
$role);
$reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name'];
$reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name'];
$personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name']; $personCenterId = $person->getAssociationMapping('center')['joinColumns'][0]['name'];
@ -111,8 +111,7 @@ class TimelineReportProvider implements TimelineProviderInterface
$parameters[] = $center->getId(); $parameters[] = $center->getId();
// loop over scopes // loop over scopes
$scopeIds = []; $scopeIds = [];
foreach ($this->helper->getReachableScopes($this->security->getUser(), foreach ($this->helper->getReachableScopes($this->security->getUser(), $role, $center) as $scope) {
$role, $center) as $scope) {
if (\in_array($scope->getId(), $scopeIds)) { if (\in_array($scope->getId(), $scopeIds)) {
continue; continue;
} }
@ -146,9 +145,9 @@ class TimelineReportProvider implements TimelineProviderInterface
private function getWhereClauseForPerson(string $context, array $args): array private function getWhereClauseForPerson(string $context, array $args): array
{ {
$role = 'CHILL_REPORT_SEE';
$report = $this->em->getClassMetadata(Report::class); $report = $this->em->getClassMetadata(Report::class);
$person = $this->em->getClassMetadata(Person::class); $person = $this->em->getClassMetadata(Person::class);
$role = new Role('CHILL_REPORT_SEE');
$reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name']; $reportPersonId = $report->getAssociationMapping('person')['joinColumns'][0]['name'];
$reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name']; $reportScopeId = $report->getAssociationMapping('scope')['joinColumns'][0]['name'];
$personCenterId = $person->getAssociationMapping('center')['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 // this is the final clause that we are going to fill
$clause = "{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})"; $clause = "{report}.{person_id} = ? AND {report}.{scopes_id} IN ({scopes_ids})";
// iterate over reachable scopes // iterate over reachable scopes
$scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, $scopes = $this->helper->getReachableScopes($this->security->getUser(), $role, $args['person']->getCenter());
$args['person']->getCenter());
foreach ($scopes as $scope) { foreach ($scopes as $scope) {
if (\in_array($scope->getId(), $parameters)) { if (\in_array($scope->getId(), $parameters)) {

View File

@ -52,7 +52,8 @@ class SingleTaskType extends AbstractType
'required' => false, 'required' => false,
'center' => $center, 'center' => $center,
'role' => TaskVoter::SHOW, 'role' => TaskVoter::SHOW,
'placeholder' => 'Not assigned' 'placeholder' => 'Not assigned',
'attr' => [ 'class' => ' select2 ']
]) ])
->add('startDate', ChillDateType::class, [ ->add('startDate', ChillDateType::class, [
'required' => false 'required' => false