diff --git a/docs/source/_static/code/exports/BirthdateFilter.php b/docs/source/_static/code/exports/BirthdateFilter.php index 91a5dc0f6..5ddcf3bfe 100644 --- a/docs/source/_static/code/exports/BirthdateFilter.php +++ b/docs/source/_static/code/exports/BirthdateFilter.php @@ -1,123 +1,124 @@ getDQLPart('where'); + // we create the clause here + $clause = $qb->expr()->between( + 'person.birthdate', + ':date_from', + ':date_to' + ); + + // we have to take care **not to** remove previous clauses... + if ($where instanceof Expr\Andx) { + $where->add($clause); + } else { + $where = $qb->expr()->andX($clause); + } + + $qb->add('where', $where); + // we add parameters from $data. $data contains the parameters from the form + $qb->setParameter('date_from', $data['date_from']); + $qb->setParameter('date_to', $data['date_to']); + } + // we give information on which type of export this filter applies public function applyOn() { return 'person'; } - public function getTitle() - { - return 'Filter by person\'s birthdate'; - } - // we build a form to collect some parameters from the users public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Born after this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + $builder->add('date_from', DateType::class, [ + 'label' => 'Born after this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Born before this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + ]); + + $builder->add('date_to', DateType::class, [ + 'label' => 'Born before this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - } - - // the form created above must be validated. The process of validation - // is executed here. This function is added by the interface - // `ExportElementValidatedInterface`, and can be ignore if there is - // no need for a validation - public function validateForm($data, ExecutionContextInterface $context) - { - $date_from = $data['date_from']; - $date_to = $data['date_to']; - - if ($date_from === null) { - $context->buildViolation('The "date from" should not be empty') - //->atPath('date_from') - ->addViolation(); - } - - if ($date_to === null) { - $context->buildViolation('The "date to" should not be empty') - //->atPath('date_to') - ->addViolation(); - } - - if ( - ($date_from !== null && $date_to !== null) - && - $date_from >= $date_to - ) { - $context->buildViolation('The date "date to" should be after the ' - . 'date given in "date from" field') - ->addViolation(); - } - } - - - // here, we alter the query created by Export - public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) - { - $where = $qb->getDQLPart('where'); - // we create the clause here - $clause = $qb->expr()->between('person.birthdate', ':date_from', - ':date_to'); - - // we have to take care **not to** remove previous clauses... - if ($where instanceof Expr\Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - // we add parameters from $data. $data contains the parameters from the form - $qb->setParameter('date_from', $data['date_from']); - $qb->setParameter('date_to', $data['date_to']); + ]); } // here, we create a simple string which will describe the action of // the filter in the Response public function describeAction($data, $format = 'string') { - return array('Filtered by person\'s birtdate: ' - . 'between %date_from% and %date_to%', array( + return ['Filtered by person\'s birtdate: ' + . 'between %date_from% and %date_to%', [ '%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() + { + return 'Filter by person\'s birthdate'; + } + // the form created above must be validated. The process of validation + // is executed here. This function is added by the interface + // `ExportElementValidatedInterface`, and can be ignore if there is + // no need for a validation + public function validateForm($data, ExecutionContextInterface $context) + { + $date_from = $data['date_from']; + $date_to = $data['date_to']; + + if (null === $date_from) { + $context->buildViolation('The "date from" should not be empty') + //->atPath('date_from') + ->addViolation(); + } + + if (null === $date_to) { + $context->buildViolation('The "date to" should not be empty') + //->atPath('date_to') + ->addViolation(); + } + + if ( + (null !== $date_from && null !== $date_to) + && $date_from >= $date_to + ) { + $context->buildViolation('The date "date to" should be after the ' + . 'date given in "date from" field') + ->addViolation(); + } + } } diff --git a/docs/source/_static/code/exports/CountPerson.php b/docs/source/_static/code/exports/CountPerson.php index 0d94c0c90..59ab604dc 100644 --- a/docs/source/_static/code/exports/CountPerson.php +++ b/docs/source/_static/code/exports/CountPerson.php @@ -1,74 +1,74 @@ - */ class CountPerson implements ExportInterface { /** - * * @var EntityManagerInterface */ protected $entityManager; public function __construct( - EntityManagerInterface $em - ) - { + EntityManagerInterface $em + ) { $this->entityManager = $em; } - public function getType() + public function buildForm(FormBuilderInterface $builder) { - return Declarations::PERSON_TYPE; + // this export does not add any form + } + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_TABULAR]; } public function getDescription() { - return "Count peoples by various parameters."; + return 'Count peoples by various parameters.'; } - public function getTitle() + public function getLabels($key, array $values, $data) { - return "Count peoples"; + // the Closure which will be executed by the formatter. + return function ($value) { + switch ($value) { + case '_header': + // we have to process specifically the '_header' string, + // which will be used by the formatter to show a column title + return $this->getTitle(); + + default: + // for all value, we do not process them and return them + // immediatly + return $value; + } + }; } - public function requiredRole() + public function getQueryKeys($data) { - return new Role(PersonVoter::STATS); - } - - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) - { - // we gather all center the user choose. - $centers = array_map(function($el) { return $el['center']; }, $acl); - - $qb = $this->entityManager->createQueryBuilder(); - - $qb->select('COUNT(person.id) AS export_result') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.center', 'center') - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - ; - - - return $qb; + // this array match the result keys in the query. We have only + // one column. + return ['export_result']; } public function getResult($qb, $data) @@ -76,44 +76,42 @@ class CountPerson implements ExportInterface return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } - public function getQueryKeys($data) + public function getTitle() { - // this array match the result keys in the query. We have only - // one column. - return array('export_result'); + return 'Count peoples'; } - public function getLabels($key, array $values, $data) + public function getType() { - - // the Closure which will be executed by the formatter. - return function($value) { - switch($value) { - case '_header': - // we have to process specifically the '_header' string, - // which will be used by the formatter to show a column title - return $this->getTitle(); - default: - // for all value, we do not process them and return them - // immediatly - return $value; - }; - }; + return Declarations::PERSON_TYPE; } - public function getAllowedFormattersTypes() + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { - return array(FormatterInterface::TYPE_TABULAR); + // we gather all center the user choose. + $centers = array_map(function ($el) { + return $el['center']; + }, $acl); + + $qb = $this->entityManager->createQueryBuilder(); + + $qb->select('COUNT(person.id) AS export_result') + ->from('ChillPersonBundle:Person', 'person') + ->join('person.center', 'center') + ->andWhere('center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); + + return $qb; } - public function buildForm(FormBuilderInterface $builder) { - // this export does not add any form + public function requiredRole() + { + return new Role(PersonVoter::STATS); } public function supportsModifiers() { // explain the export manager which formatters and filters are allowed - return array(Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN); + return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN]; } - } diff --git a/docs/source/development/pagination/example.php b/docs/source/development/pagination/example.php index 71dcb263c..37e824e3f 100644 --- a/docs/source/development/pagination/example.php +++ b/docs/source/development/pagination/example.php @@ -1,20 +1,25 @@ getDoctrine()->getManager(); // first, get the number of total item are available $total = $em - ->createQuery("SELECT COUNT (item.id) FROM ChillMyBundle:Item item") - ->getSingleScalarResult(); + ->createQuery('SELECT COUNT (item.id) FROM ChillMyBundle:Item item') + ->getSingleScalarResult(); // get the PaginatorFactory $paginatorFactory = $this->get('chill_main.paginator_factory'); @@ -25,7 +30,7 @@ class ItemController extends Controller { // launch your query on item. Limit the query to the results // for the current page using the paginator - $items = $em->createQuery("SELECT item FROM ChillMyBundle:Item item WHERE ") + $items = $em->createQuery('SELECT item FROM ChillMyBundle:Item item WHERE ') // use the paginator to get the first item number ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) // use the paginator to get the number of items to display @@ -34,12 +39,10 @@ class ItemController extends Controller { return $this ->render( 'ChillMyBundle:Item:list.html.twig', - array( + [ 'items' => $items, - 'paginator' => $paginator - ) + 'paginator' => $paginator, + ] ); } - } - diff --git a/docs/source/development/useful-snippets/controller-secured-for-person.php b/docs/source/development/useful-snippets/controller-secured-for-person.php index 501fb46c1..126a8cad4 100644 --- a/docs/source/development/useful-snippets/controller-secured-for-person.php +++ b/docs/source/development/useful-snippets/controller-secured-for-person.php @@ -1,43 +1,51 @@ get('chill.person.repository.person') ->find($id); - - if ($person === null) { - throw $this->createNotFoundException("The person is not found"); + + if (null === $person) { + throw $this->createNotFoundException('The person is not found'); } - + $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - + /* @var $authorizationHelper \Chill\MainBundle\Security\Authorization\AuthorizationHelper */ $authorizationHelper = $this->get('chill.main.security.' . 'authorization.helper'); - + $circles = $authorizationHelper->getReachableCircles( - $this->getUser(), - new Role(ConsultationVoter::SEE), + $this->getUser(), + new Role(ConsultationVoter::SEE), $person->getCenter() - ); - - // create a query which take circles into account + ); + + // create a query which take circles into account $consultations = $this->getDoctrine()->getManager() ->createQuery('SELECT c FROM ChillHealthBundle:Consultation c ' . 'WHERE c.patient = :person AND c.circle IN(:circles) ' @@ -45,11 +53,10 @@ class ConsultationController extends Controller ->setParameter('person', $person) ->setParameter('circles', $circles) ->getResult(); - - return $this->render('ChillHealthBundle:Consultation:list.html.twig', array( - 'person' => $person, - 'consultations' => $consultations - )); + + return $this->render('ChillHealthBundle:Consultation:list.html.twig', [ + 'person' => $person, + 'consultations' => $consultations, + ]); } } - diff --git a/docs/source/development/user-interface/widgets/ChillMainConfiguration.php b/docs/source/development/user-interface/widgets/ChillMainConfiguration.php index 2cc893cc3..7b088c020 100644 --- a/docs/source/development/user-interface/widgets/ChillMainConfiguration.php +++ b/docs/source/development/user-interface/widgets/ChillMainConfiguration.php @@ -1,64 +1,60 @@ setWidgetFactories($widgetFactories); - // we will need the container builder later... - $this->containerBuilder = $containerBuilder; - } - - /** - * {@inheritDoc} - */ - public function getConfigTreeBuilder() - { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('chill_main'); + /** + * @var ContainerBuilder + */ + private $containerBuilder; - $rootNode - ->children() + public function __construct( + array $widgetFactories = [], + ContainerBuilder $containerBuilder + ) { + // we register here widget factories (see below) + $this->setWidgetFactories($widgetFactories); + // we will need the container builder later... + $this->containerBuilder = $containerBuilder; + } - // ... + public function getConfigTreeBuilder() + { + $treeBuilder = new TreeBuilder(); + $rootNode = $treeBuilder->root('chill_main'); - ->arrayNode('widgets') - ->canBeDisabled() - ->children() - // we declare here all configuration for homepage place - ->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder)) - ->end() // end of widgets/children - ->end() // end of widgets - ->end() // end of root/children - ->end() // end of root - ; - - - return $treeBuilder; - } - } + $rootNode + ->children() + // ... + ->arrayNode('widgets') + ->canBeDisabled() + ->children() + // we declare here all configuration for homepage place + ->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder)) + ->end() // end of widgets/children + ->end() // end of widgets + ->end() // end of root/children + ->end(); // end of root + return $treeBuilder; + } +} diff --git a/docs/source/development/user-interface/widgets/ChillMainExtension.php b/docs/source/development/user-interface/widgets/ChillMainExtension.php index 4370f33f2..1a784fd5f 100644 --- a/docs/source/development/user-interface/widgets/ChillMainExtension.php +++ b/docs/source/development/user-interface/widgets/ChillMainExtension.php @@ -1,16 +1,17 @@ widgetFactories[] = $factory; } - + + public function getConfiguration(array $config, ContainerBuilder $container) + { + return new Configuration($this->widgetFactories, $container); + } + /** - * * @return WidgetFactoryInterface[] */ public function getWidgetFactories() { return $this->widgetFactories; } - + public function load(array $configs, ContainerBuilder $container) { // configuration for main bundle $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); - - // add the key 'widget' without the key 'enable' - $container->setParameter('chill_main.widgets', - array('homepage' => $config['widgets']['homepage'])); - // ... + // add the key 'widget' without the key 'enable' + $container->setParameter( + 'chill_main.widgets', + ['homepage' => $config['widgets']['homepage']] + ); + + // ... } - - public function getConfiguration(array $config, ContainerBuilder $container) - { - return new Configuration($this->widgetFactories, $container); - } - } diff --git a/docs/source/development/user-interface/widgets/ChillPersonAddAPersonListWidgetFactory.php b/docs/source/development/user-interface/widgets/ChillPersonAddAPersonListWidgetFactory.php index e5bd236c9..f3a93a3e6 100644 --- a/docs/source/development/user-interface/widgets/ChillPersonAddAPersonListWidgetFactory.php +++ b/docs/source/development/user-interface/widgets/ChillPersonAddAPersonListWidgetFactory.php @@ -1,69 +1,71 @@ booleanNode('only_active') - ->defaultTrue() - ->end(); + ->defaultTrue() + ->end(); $node->integerNode('number_of_items') ->defaultValue(50) ->end(); $node->scalarNode('filtering_class') - ->defaultNull() - ->end(); - + ->defaultNull() + ->end(); } - - /* - * return an array with the allowed places where the widget can be rendered - * - * @return string[] - */ + + /* + * return an array with the allowed places where the widget can be rendered + * + * @return string[] + */ public function getAllowedPlaces() { - return array('homepage'); + return ['homepage']; } - - /* - * return the widget alias - * - * @return string - */ - public function getWidgetAlias() - { - return 'person_list'; - } - + /* * return the service id for the service which will render the widget. * * this service must implements `Chill\MainBundle\Templating\Widget\WidgetInterface` - * - * the service must exists in the container, and it is not required that the service + * + * the service must exists in the container, and it is not required that the service * has the `chill_main` tag. */ public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config) { return 'chill_person.widget.person_list'; } - -} + /* + * return the widget alias + * + * @return string + */ + public function getWidgetAlias() + { + return 'person_list'; + } +} diff --git a/docs/source/development/user-interface/widgets/ChillPersonAddAPersonWidget.php b/docs/source/development/user-interface/widgets/ChillPersonAddAPersonWidget.php index 876848d23..d74c7936b 100644 --- a/docs/source/development/user-interface/widgets/ChillPersonAddAPersonWidget.php +++ b/docs/source/development/user-interface/widgets/ChillPersonAddAPersonWidget.php @@ -1,66 +1,71 @@ personRepository = $personRepostory; $this->authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; @@ -68,27 +73,24 @@ class PersonListWidget implements WidgetInterface } /** - * * @param type $place - * @param array $context - * @param array $config + * * @return string */ - public function render(\Twig_Environment $env, $place, array $context, array $config) - { + public function render(Twig_Environment $env, $place, array $context, array $config) + { $qb = $this->personRepository - ->createQueryBuilder('person'); - + ->createQueryBuilder('person'); + // show only the person from the authorized centers $and = $qb->expr()->andX(); $centers = $this->authorizationHelper - ->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE)); + ->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE)); $and->add($qb->expr()->in('person.center', ':centers')); $qb->setParameter('centers', $centers); - // add the "only active" where clause - if ($config['only_active'] === true) { + if (true === $config['only_active']) { $qb->join('person.accompanyingPeriods', 'ap'); $or = new Expr\Orx(); // add the case where closingDate IS NULL @@ -98,32 +100,30 @@ class PersonListWidget implements WidgetInterface $or->add($andWhenClosingDateIsNull); // add the case when now is between opening date and closing date $or->add( - (new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate') - ); + (new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate') + ); $and->add($or); - $qb->setParameter('now', new \DateTime(), Type::DATE); + $qb->setParameter('now', new DateTime(), Type::DATE); } - + // adding the where clause to the query $qb->where($and); - + $qb->setFirstResult(0)->setMaxResults($config['number_of_items']); - + $persons = $qb->getQuery()->getResult(); - + return $env->render( 'ChillPersonBundle:Widget:homepage_person_list.html.twig', - array('persons' => $persons) - ); + ['persons' => $persons] + ); } - + /** - * * @return UserInterface */ private function getUser() { // return a user } - } diff --git a/docs/source/development/user-interface/widgets/ChillPersonExtension.php b/docs/source/development/user-interface/widgets/ChillPersonExtension.php index 869931184..b5ed095a0 100644 --- a/docs/source/development/user-interface/widgets/ChillPersonExtension.php +++ b/docs/source/development/user-interface/widgets/ChillPersonExtension.php @@ -1,51 +1,46 @@ prependExtensionConfig('chill_main', array( - 'widgets' => array( - 'homepage' => array( - array( + $container->prependExtensionConfig('chill_main', [ + 'widgets' => [ + 'homepage' => [ + [ 'widget_alias' => 'add_person', - 'order' => 2 - ) - ) - ) - )); + 'order' => 2, + ], + ], + ], + ]); } } - diff --git a/src/Bundle/ChillActivityBundle/ChillActivityBundle.php b/src/Bundle/ChillActivityBundle/ChillActivityBundle.php index 36c396474..f449ac07f 100644 --- a/src/Bundle/ChillActivityBundle/ChillActivityBundle.php +++ b/src/Bundle/ChillActivityBundle/ChillActivityBundle.php @@ -1,5 +1,12 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Controller; +use Chill\ActivityBundle\Entity\Activity; +use Chill\ActivityBundle\Form\ActivityType; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Privacy\PrivacyEvent; +use DateTime; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Role\Role; -use Chill\ActivityBundle\Entity\Activity; -use Chill\PersonBundle\Entity\Person; -use Chill\ActivityBundle\Form\ActivityType; /** - * Class ActivityController - * - * @package Chill\ActivityBundle\Controller + * Class ActivityController. */ class ActivityController extends AbstractController { + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; /** * @var EventDispatcherInterface */ protected $eventDispatcher; - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; - /** * @var LoggerInterface */ @@ -59,9 +43,6 @@ class ActivityController extends AbstractController /** * ActivityController constructor. - * - * @param EventDispatcherInterface $eventDispatcher - * @param AuthorizationHelper $authorizationHelper */ public function __construct( EventDispatcherInterface $eventDispatcher, @@ -73,52 +54,17 @@ class ActivityController extends AbstractController $this->logger = $logger; } - /** - * Lists all Activity entities. - * - */ - public function listAction($person_id, Request $request) - { - $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - if ($person === NULL) { - throw $this->createNotFoundException('Person not found'); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $reachableScopes = $this->authorizationHelper - ->getReachableScopes($this->getUser(), new Role('CHILL_ACTIVITY_SEE'), - $person->getCenter()); - - $activities = $em->getRepository('ChillActivityBundle:Activity') - ->findBy( - array('person' => $person, 'scope' => $reachableScopes), - array('date' => 'DESC') - ); - - $event = new PrivacyEvent($person, array( - 'element_class' => Activity::class, - 'action' => 'list' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillActivityBundle:Activity:list.html.twig', array( - 'activities' => $activities, - 'person' => $person - )); - } /** * Creates a new Activity entity. * + * @param mixed $person_id */ public function createAction($person_id, Request $request) { $em = $this->getDoctrine()->getManager(); $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - if ($person === NULL) { + if (null === $person) { throw $this->createNotFoundException('person not found'); } @@ -132,133 +78,115 @@ class ActivityController extends AbstractController if ($form->isValid()) { $em = $this->getDoctrine()->getManager(); - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity, - 'creation of this activity not allowed'); + $this->denyAccessUnlessGranted( + 'CHILL_ACTIVITY_CREATE', + $entity, + 'creation of this activity not allowed' + ); $em->persist($entity); $em->flush(); $this->get('session') ->getFlashBag() - ->add('success', + ->add( + 'success', $this->get('translator') ->trans('Success : activity created!') ); return $this->redirect( - $this->generateUrl('chill_activity_activity_show', - array('id' => $entity->getId(), 'person_id' => $person_id))); + $this->generateUrl( + 'chill_activity_activity_show', + ['id' => $entity->getId(), 'person_id' => $person_id] + ) + ); } $this->get('session') - ->getFlashBag()->add('danger', + ->getFlashBag()->add( + 'danger', $this->get('translator') ->trans('The form is not valid. The activity has not been created !') ); - return $this->render('ChillActivityBundle:Activity:new.html.twig', array( + return $this->render('ChillActivityBundle:Activity:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - 'person' => $person - )); + 'form' => $form->createView(), + 'person' => $person, + ]); } /** - * Creates a form to create a Activity entity. + * Deletes a Activity entity. * - * @param Activity $entity The entity - * - * @return \Symfony\Component\Form\Form The form + * @param mixed $id + * @param mixed $person_id */ - private function createCreateForm(Activity $entity) - { - $form = $this->createForm(ActivityType::class, $entity, - array( - 'action' => $this->generateUrl('chill_activity_activity_create', [ - 'person_id' => $entity->getPerson()->getId(), - ]), - 'method' => 'POST', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_CREATE') - ) - ); - - return $form; - } - - /** - * Displays a form to create a new Activity entity. - * - */ - public function newAction($person_id) + public function deleteAction(Request $request, $id, $person_id) { $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - if ($person === NULL){ - throw $this->createNotFoundException('Person not found'); - } + /* @var $activity Activity */ + $activity = $em->getRepository('ChillActivityBundle:Activity') + ->find($id); + $person = $activity->getPerson(); - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $entity = new Activity(); - $entity->setUser($this->get('security.token_storage')->getToken()->getUser()); - $entity->setPerson($person); - $entity->setDate(new \DateTime('now')); - - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); - - $form = $this->createCreateForm($entity, $person); - - return $this->render('ChillActivityBundle:Activity:new.html.twig', array( - 'person' => $person, - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Activity entity. - * - */ - public function showAction($person_id, $id) - { - $em = $this->getDoctrine()->getManager(); - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - if (!$person) { - throw $this->createNotFoundException('person not found'); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); - - if (!$entity) { + if (!$activity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); + $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); - $deleteForm = $this->createDeleteForm($id, $person); + $form = $this->createDeleteForm($id, $person); - $event = new PrivacyEvent($person, array( - 'element_class' => Activity::class, - 'element_id' => $entity->getId(), - 'action' => 'show' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); - return $this->render('ChillActivityBundle:Activity:show.html.twig', array( - 'person' => $person, - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - )); + if ($form->isValid()) { + $this->logger->notice('An activity has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'activity_id' => $activity->getId(), + 'person_id' => $activity->getPerson()->getId(), + 'comment' => $activity->getComment()->getComment(), + 'scope_id' => $activity->getScope()->getId(), + 'reasons_ids' => $activity->getReasons() + ->map(function ($ar) { + return $ar->getId(); + }) + ->toArray(), + 'type_id' => $activity->getType()->getId(), + 'duration' => $activity->getDurationTime()->format('U'), + 'date' => $activity->getDate()->format('Y-m-d'), + 'attendee' => $activity->getAttendee(), + ]); + + $em->remove($activity); + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The activity has been successfully removed.')); + + return $this->redirect($this->generateUrl( + 'chill_activity_activity_list', + [ + 'person_id' => $person_id, + ] + )); + } + } + + return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', [ + 'activity' => $activity, + 'delete_form' => $form->createView(), + ]); } /** * Displays a form to edit an existing Activity entity. * + * @param mixed $person_id + * @param mixed $id */ public function editAction($person_id, $id) { @@ -282,46 +210,140 @@ class ActivityController extends AbstractController $editForm = $this->createEditForm($entity); $deleteForm = $this->createDeleteForm($id, $person); - $event = new PrivacyEvent($person, array( + $event = new PrivacyEvent($person, [ 'element_class' => Activity::class, 'element_id' => $entity->getId(), - 'action' => 'edit' - )); + 'action' => 'edit', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), + return $this->render('ChillActivityBundle:Activity:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), 'delete_form' => $deleteForm->createView(), - 'person' => $person - )); + 'person' => $person, + ]); } /** - * Creates a form to edit a Activity entity. - * - * @param Activity $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Activity $entity) + * Lists all Activity entities. + * + * @param mixed $person_id + */ + public function listAction($person_id, Request $request) { - $form = $this->createForm(ActivityType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activity_update', - array( - 'id' => $entity->getId(), - 'person_id' => $entity->getPerson()->getId() - )), - 'method' => 'PUT', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_ACTIVITY_UPDATE') - )); + $em = $this->getDoctrine()->getManager(); + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - return $form; + if (null === $person) { + throw $this->createNotFoundException('Person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $reachableScopes = $this->authorizationHelper + ->getReachableScopes( + $this->getUser(), + new Role('CHILL_ACTIVITY_SEE'), + $person->getCenter() + ); + + $activities = $em->getRepository('ChillActivityBundle:Activity') + ->findBy( + ['person' => $person, 'scope' => $reachableScopes], + ['date' => 'DESC'] + ); + + $event = new PrivacyEvent($person, [ + 'element_class' => Activity::class, + 'action' => 'list', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillActivityBundle:Activity:list.html.twig', [ + 'activities' => $activities, + 'person' => $person, + ]); } + + /** + * Displays a form to create a new Activity entity. + * + * @param mixed $person_id + */ + public function newAction($person_id) + { + $em = $this->getDoctrine()->getManager(); + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + + if (null === $person) { + throw $this->createNotFoundException('Person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $entity = new Activity(); + $entity->setUser($this->get('security.token_storage')->getToken()->getUser()); + $entity->setPerson($person); + $entity->setDate(new DateTime('now')); + + $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); + + $form = $this->createCreateForm($entity, $person); + + return $this->render('ChillActivityBundle:Activity:new.html.twig', [ + 'person' => $person, + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Activity entity. + * + * @param mixed $person_id + * @param mixed $id + */ + public function showAction($person_id, $id) + { + $em = $this->getDoctrine()->getManager(); + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + + if (!$person) { + throw $this->createNotFoundException('person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Activity entity.'); + } + + $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); + + $deleteForm = $this->createDeleteForm($id, $person); + + $event = new PrivacyEvent($person, [ + 'element_class' => Activity::class, + 'element_id' => $entity->getId(), + 'action' => 'show', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillActivityBundle:Activity:show.html.twig', [ + 'person' => $person, + 'entity' => $entity, + 'delete_form' => $deleteForm->createView(), + ]); + } + /** * Edits an existing Activity entity. * + * @param mixed $person_id + * @param mixed $id */ public function updateAction(Request $request, $person_id, $id) { @@ -340,11 +362,11 @@ class ActivityController extends AbstractController $editForm = $this->createEditForm($entity); $editForm->handleRequest($request); - $event = new PrivacyEvent($person, array( + $event = new PrivacyEvent($person, [ 'element_class' => Activity::class, 'element_id' => $entity->getId(), - 'action' => 'update' - )); + 'action' => 'update', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); if ($editForm->isValid()) { @@ -352,95 +374,59 @@ class ActivityController extends AbstractController $this->get('session') ->getFlashBag() - ->add('success', + ->add( + 'success', $this->get('translator') ->trans('Success : activity updated!') ); - return $this->redirect($this->generateUrl('chill_activity_activity_show', array('id' => $id, 'person_id' => $person_id))); + return $this->redirect($this->generateUrl('chill_activity_activity_show', ['id' => $id, 'person_id' => $person_id])); } $this->get('session') ->getFlashBag() - ->add('error', + ->add( + 'error', $this->get('translator') ->trans('This form contains errors') ); - return $this->render('ChillActivityBundle:Activity:edit.html.twig', array( - 'person' => $entity->getPerson(), - 'entity' => $entity, - 'edit_form' => $editForm->createView(), + return $this->render('ChillActivityBundle:Activity:edit.html.twig', [ + 'person' => $entity->getPerson(), + 'entity' => $entity, + 'edit_form' => $editForm->createView(), 'delete_form' => $deleteForm->createView(), - )); + ]); } /** - * Deletes a Activity entity. + * Creates a form to create a Activity entity. * + * @param Activity $entity The entity + * + * @return \Symfony\Component\Form\Form The form */ - public function deleteAction(Request $request, $id, $person_id) + private function createCreateForm(Activity $entity) { - $em = $this->getDoctrine()->getManager(); - - /* @var $activity Activity */ - $activity = $em->getRepository('ChillActivityBundle:Activity') - ->find($id); - $person = $activity->getPerson(); - - if (!$activity) { - throw $this->createNotFoundException('Unable to find Activity entity.'); - } - - $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); - - $form = $this->createDeleteForm($id, $person); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - - $this->logger->notice("An activity has been removed", array( - 'by_user' => $this->getUser()->getUsername(), - 'activity_id' => $activity->getId(), - 'person_id' => $activity->getPerson()->getId(), - 'comment' => $activity->getComment()->getComment(), - 'scope_id' => $activity->getScope()->getId(), - 'reasons_ids' => $activity->getReasons() - ->map(function ($ar) { return $ar->getId(); }) - ->toArray(), - 'type_id' => $activity->getType()->getId(), - 'duration' => $activity->getDurationTime()->format('U'), - 'date' => $activity->getDate()->format('Y-m-d'), - 'attendee' => $activity->getAttendee() - )); - - $em->remove($activity); - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans("The activity has been successfully removed.")); - - return $this->redirect($this->generateUrl( - 'chill_activity_activity_list', array( - 'person_id' => $person_id - ))); - } - } - - return $this->render('ChillActivityBundle:Activity:confirm_delete.html.twig', array( - 'activity' => $activity, - 'delete_form' => $form->createView() - )); - - + return $this->createForm( + ActivityType::class, + $entity, + [ + 'action' => $this->generateUrl('chill_activity_activity_create', [ + 'person_id' => $entity->getPerson()->getId(), + ]), + 'method' => 'POST', + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + ] + ); } /** * Creates a form to delete a Activity entity by id. * * @param mixed $id The entity id + * @param mixed $person * * @return \Symfony\Component\Form\Form The form */ @@ -449,10 +435,33 @@ class ActivityController extends AbstractController return $this->createFormBuilder() ->setAction($this->generateUrl( 'chill_activity_activity_delete', - array('id' => $id, 'person_id' => $person->getId()))) + ['id' => $id, 'person_id' => $person->getId()] + )) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + /** + * Creates a form to edit a Activity entity. + * + * @param Activity $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Activity $entity) + { + return $this->createForm(ActivityType::class, $entity, [ + 'action' => $this->generateUrl( + 'chill_activity_activity_update', + [ + 'id' => $entity->getId(), + 'person_id' => $entity->getPerson()->getId(), + ] + ), + 'method' => 'PUT', + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_ACTIVITY_UPDATE'), + ]); } } diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php index 793c9c695..792b528b9 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonCategoryController.php @@ -1,38 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll(); - - return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new ActivityReasonCategory entity. - * */ public function createAction(Request $request) { @@ -45,71 +34,19 @@ class ActivityReasonCategoryController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_show', ['id' => $entity->getId()])); } - return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array( + return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a ActivityReasonCategory entity. - * - * @param ActivityReasonCategory $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(ActivityReasonCategory $entity) - { - $form = $this->createForm(ActivityReasonCategoryType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new ActivityReasonCategory entity. - * - */ - public function newAction() - { - $entity = new ActivityReasonCategory(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a ActivityReasonCategory entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.'); - } - - return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', array( - 'entity' => $entity, - )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing ActivityReasonCategory entity. * + * @param mixed $id */ public function editAction($id) { @@ -123,33 +60,64 @@ class ActivityReasonCategoryController extends AbstractController $editForm = $this->createEditForm($entity); - return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a ActivityReasonCategory entity. - * - * @param ActivityReasonCategory $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(ActivityReasonCategory $entity) + * Lists all ActivityReasonCategory entities. + */ + public function indexAction() { - $form = $this->createForm(ActivityReasonCategoryType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); + $em = $this->getDoctrine()->getManager(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + $entities = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->findAll(); - return $form; + return $this->render('ChillActivityBundle:ActivityReasonCategory:index.html.twig', [ + 'entities' => $entities, + ]); } + + /** + * Displays a form to create a new ActivityReasonCategory entity. + */ + public function newAction() + { + $entity = new ActivityReasonCategory(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillActivityBundle:ActivityReasonCategory:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a ActivityReasonCategory entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillActivityBundle:ActivityReasonCategory')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find ActivityReasonCategory entity.'); + } + + return $this->render('ChillActivityBundle:ActivityReasonCategory:show.html.twig', [ + 'entity' => $entity, + ]); + } + /** * Edits an existing ActivityReasonCategory entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -167,12 +135,50 @@ class ActivityReasonCategoryController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('chill_activity_activityreasoncategory_edit', ['id' => $id])); } - return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillActivityBundle:ActivityReasonCategory:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a ActivityReasonCategory entity. + * + * @param ActivityReasonCategory $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(ActivityReasonCategory $entity) + { + $form = $this->createForm(ActivityReasonCategoryType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activityreasoncategory_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a ActivityReasonCategory entity. + * + * @param ActivityReasonCategory $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(ActivityReasonCategory $entity) + { + $form = $this->createForm(ActivityReasonCategoryType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activityreasoncategory_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php index 6afeceac7..4e61fa754 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityReasonController.php @@ -1,38 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll(); - - return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new ActivityReason entity. - * */ public function createAction(Request $request) { @@ -45,71 +34,19 @@ class ActivityReasonController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $entity->getId()])); } - return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array( + return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a ActivityReason entity. - * - * @param ActivityReason $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(ActivityReason $entity) - { - $form = $this->createForm(ActivityReasonType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activityreason_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new ActivityReason entity. - * - */ - public function newAction() - { - $entity = new ActivityReason(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a ActivityReason entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityReason entity.'); - } - - return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', array( - 'entity' => $entity, - )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing ActivityReason entity. * + * @param mixed $id */ public function editAction($id) { @@ -123,33 +60,64 @@ class ActivityReasonController extends AbstractController $editForm = $this->createEditForm($entity); - return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView() - )); + return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a ActivityReason entity. - * - * @param ActivityReason $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(ActivityReason $entity) + * Lists all ActivityReason entities. + */ + public function indexAction() { - $form = $this->createForm(ActivityReasonType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activityreason_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); + $em = $this->getDoctrine()->getManager(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + $entities = $em->getRepository('ChillActivityBundle:ActivityReason')->findAll(); - return $form; + return $this->render('ChillActivityBundle:ActivityReason:index.html.twig', [ + 'entities' => $entities, + ]); } + + /** + * Displays a form to create a new ActivityReason entity. + */ + public function newAction() + { + $entity = new ActivityReason(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillActivityBundle:ActivityReason:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a ActivityReason entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillActivityBundle:ActivityReason')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find ActivityReason entity.'); + } + + return $this->render('ChillActivityBundle:ActivityReason:show.html.twig', [ + 'entity' => $entity, + ]); + } + /** * Edits an existing ActivityReason entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -167,12 +135,50 @@ class ActivityReasonController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activityreason', array('id' => $id))); + return $this->redirect($this->generateUrl('chill_activity_activityreason', ['id' => $id])); } - return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView() - )); + return $this->render('ChillActivityBundle:ActivityReason:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a ActivityReason entity. + * + * @param ActivityReason $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(ActivityReason $entity) + { + $form = $this->createForm(ActivityReasonType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activityreason_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a ActivityReason entity. + * + * @param ActivityReason $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(ActivityReason $entity) + { + $form = $this->createForm(ActivityReasonType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activityreason_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php b/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php index f27bea0ae..c7455de36 100644 --- a/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php +++ b/src/Bundle/ChillActivityBundle/Controller/ActivityTypeController.php @@ -1,38 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll(); - - return $this->render('ChillActivityBundle:ActivityType:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new ActivityType entity. - * */ public function createAction(Request $request) { @@ -45,71 +34,19 @@ class ActivityTypeController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activitytype_show', array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl('chill_activity_activitytype_show', ['id' => $entity->getId()])); } - return $this->render('ChillActivityBundle:ActivityType:new.html.twig', array( + return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a ActivityType entity. - * - * @param ActivityType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(ActivityType $entity) - { - $form = $this->createForm(ActivityTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activitytype_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new ActivityType entity. - * - */ - public function newAction() - { - $entity = new ActivityType(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillActivityBundle:ActivityType:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a ActivityType entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find ActivityType entity.'); - } - - return $this->render('ChillActivityBundle:ActivityType:show.html.twig', array( - 'entity' => $entity, - )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing ActivityType entity. * + * @param mixed $id */ public function editAction($id) { @@ -123,33 +60,64 @@ class ActivityTypeController extends AbstractController $editForm = $this->createEditForm($entity); - return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView() - )); + return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a ActivityType entity. - * - * @param ActivityType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(ActivityType $entity) + * Lists all ActivityType entities. + */ + public function indexAction() { - $form = $this->createForm(ActivityTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_activity_activitytype_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); + $em = $this->getDoctrine()->getManager(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + $entities = $em->getRepository('ChillActivityBundle:ActivityType')->findAll(); - return $form; + return $this->render('ChillActivityBundle:ActivityType:index.html.twig', [ + 'entities' => $entities, + ]); } + + /** + * Displays a form to create a new ActivityType entity. + */ + public function newAction() + { + $entity = new ActivityType(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillActivityBundle:ActivityType:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a ActivityType entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillActivityBundle:ActivityType')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find ActivityType entity.'); + } + + return $this->render('ChillActivityBundle:ActivityType:show.html.twig', [ + 'entity' => $entity, + ]); + } + /** * Edits an existing ActivityType entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -167,12 +135,50 @@ class ActivityTypeController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('chill_activity_activitytype_edit', ['id' => $id])); } - return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillActivityBundle:ActivityType:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a ActivityType entity. + * + * @param ActivityType $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(ActivityType $entity) + { + $form = $this->createForm(ActivityTypeType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activitytype_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a ActivityType entity. + * + * @param ActivityType $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(ActivityType $entity) + { + $form = $this->createForm(ActivityTypeType::class, $entity, [ + 'action' => $this->generateUrl('chill_activity_activitytype_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillActivityBundle/Controller/AdminController.php b/src/Bundle/ChillActivityBundle/Controller/AdminController.php index 0150b44d0..16de242fb 100644 --- a/src/Bundle/ChillActivityBundle/Controller/AdminController.php +++ b/src/Bundle/ChillActivityBundle/Controller/AdminController.php @@ -1,33 +1,18 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Controller; -use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; /** - * Controller for activity configuration - * - * @author Julien Fastré - * @author Champs Libres + * Controller for activity configuration. */ class AdminController extends AbstractController { @@ -35,7 +20,7 @@ class AdminController extends AbstractController { return $this->render('ChillActivityBundle:Admin:layout_activity.html.twig'); } - + public function redirectToAdminIndexAction() { return $this->redirectToRoute('chill_main_admin_central'); diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php index dd24cfcd2..c9fc4e09c 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivity.php @@ -1,42 +1,25 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Entity\Activity; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\DataFixtures\ORM\LoadUsers; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; use Faker\Factory as FakerFactory; -use Chill\ActivityBundle\Entity\Activity; -use Chill\MainBundle\DataFixtures\ORM\LoadUsers; -use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityReason; -use Chill\ActivityBundle\DataFixtures\ORM\LoadActivityType; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; use Symfony\Component\DependencyInjection\ContainerAwareInterface; /** - * Load reports into DB - * - * @author Champs-Libres Coop + * Load reports into DB. */ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { @@ -57,30 +40,48 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C return 16400; } - /** - * Return a random scope - * - * @return \Chill\MainBundle\Entity\Scope - */ - private function getRandomScope() + public function load(ObjectManager $manager) { - $scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)]; - return $this->getReference($scopeRef); + $persons = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillPersonBundle:Person') + ->findAll(); + + foreach ($persons as $person) { + $activityNbr = rand(0, 3); + + for ($i = 0; $i < $activityNbr; ++$i) { + echo 'Creating an activity type for : ' . $person . "\n"; + $activity = $this->newRandomActivity($person); + $manager->persist($activity); + } + } + $manager->flush(); + } + + public function newRandomActivity($person) + { + $activity = (new Activity()) + ->setUser($this->getRandomUser()) + ->setPerson($person) + ->setDate($this->faker->dateTimeThisYear()) + ->setDurationTime($this->faker->dateTime(36000)) + ->setType($this->getRandomActivityType()) + ->setScope($this->getRandomScope()) + ->setAttendee($this->faker->boolean()); + + $usedId = []; + + for ($i = 0; rand(0, 4) > $i; ++$i) { + $reason = $this->getRandomActivityReason($usedId); + $usedId[] = $reason->getId(); + $activity->addReason($reason); + } + + return $activity; } /** - * Return a random activityType - * - * @return \Chill\ActivityBundle\Entity\ActivityType - */ - private function getRandomActivityType() - { - $typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)]; - return $this->getReference($typeRef); - } - - /** - * Return a random activityReason + * Return a random activityReason. * * @return \Chill\ActivityBundle\Entity\ActivityReason */ @@ -97,52 +98,38 @@ class LoadActivity extends AbstractFixture implements OrderedFixtureInterface, C } /** - * Return a random user + * Return a random activityType. + * + * @return \Chill\ActivityBundle\Entity\ActivityType + */ + private function getRandomActivityType() + { + $typeRef = LoadActivityType::$references[array_rand(LoadActivityType::$references)]; + + return $this->getReference($typeRef); + } + + /** + * Return a random scope. + * + * @return \Chill\MainBundle\Entity\Scope + */ + private function getRandomScope() + { + $scopeRef = LoadScopes::$references[array_rand(LoadScopes::$references)]; + + return $this->getReference($scopeRef); + } + + /** + * Return a random user. * * @return \Chill\MainBundle\Entity\User */ private function getRandomUser() { $userRef = array_rand(LoadUsers::$refs); + return $this->getReference($userRef); } - - public function newRandomActivity($person) - { - $activity = (new Activity()) - ->setUser($this->getRandomUser()) - ->setPerson($person) - ->setDate($this->faker->dateTimeThisYear()) - ->setDurationTime($this->faker->dateTime(36000)) - ->setType($this->getRandomActivityType()) - ->setScope($this->getRandomScope()) - ->setAttendee($this->faker->boolean()) - ; - - $usedId = array(); - for ($i = 0; $i < rand(0, 4); $i++) { - $reason = $this->getRandomActivityReason($usedId); - $usedId[] = $reason->getId(); - $activity->addReason($reason); - } - - return $activity; - } - - public function load(ObjectManager $manager) - { - $persons = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillPersonBundle:Person') - ->findAll(); - - foreach($persons as $person) { - $activityNbr = rand(0,3); - for($i = 0; $i < $activityNbr; $i ++) { - print "Creating an activity type for : ".$person."\n"; - $activity = $this->newRandomActivity($person); - $manager->persist($activity); - } - } - $manager->flush(); - } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReason.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReason.php index 3915fc3af..f840c988b 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReason.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReason.php @@ -1,81 +1,66 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Entity\ActivityReason; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\ActivityBundle\Entity\ActivityReason; /** - * Description of LoadActivityReason - * - * @author Champs-Libres Coop + * Description of LoadActivityReason. */ class LoadActivityReason extends AbstractFixture implements OrderedFixtureInterface { + public static $references = []; + public function getOrder() { return 16300; } - - public static $references = array(); - + public function load(ObjectManager $manager) { $reasons = [ [ 'name' => ['fr' => 'Recherche logement', 'en' => 'Housing research', 'nl' => 'Woning zoektoch'], - 'category' => 'cat_Housing'], + 'category' => 'cat_Housing', ], [ 'name' => ['fr' => 'Problème avec propriétaire', 'en' => 'Landlord problems', 'nl' => 'Huisbaas problemen'], - 'category' => 'cat_Housing'], + 'category' => 'cat_Housing', ], [ 'name' => ['fr' => 'Retard de payement', 'en' => 'Payement problems', 'nl' => 'Betalings vertragingen'], - 'category' => 'cat_Housing'], + 'category' => 'cat_Housing', ], [ 'name' => ['fr' => 'Explication législation', 'en' => 'Legislation explanation', 'nl' => 'Legislative uitleg'], - 'category' => 'cat_Unemployment procedure'], + 'category' => 'cat_Unemployment procedure', ], [ 'name' => ['fr' => 'Coaching entretien d\'activation', 'en' => 'Interview coaching', 'nl' => 'Interview coaching'], - 'category' => 'cat_Unemployment procedure'], + 'category' => 'cat_Unemployment procedure', ], [ 'name' => ['fr' => 'Récupération des allocations', 'en' => 'Allowance recovery', 'nl' => 'Terugwinning van de uitkeringen'], - 'category' => 'cat_Unemployment procedure'] + 'category' => 'cat_Unemployment procedure', ], ]; - + foreach ($reasons as $r) { - print "Creating activity reason : " . $r['name']['en'] . "\n"; + echo 'Creating activity reason : ' . $r['name']['en'] . "\n"; $activityReason = (new ActivityReason()) ->setName(($r['name'])) ->setActive(true) ->setCategory($this->getReference($r['category'])); $manager->persist($activityReason); - $reference = 'activity_reason_'.$r['name']['en']; + $reference = 'activity_reason_' . $r['name']['en']; $this->addReference($reference, $activityReason); static::$references[] = $reference; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReasonCategory.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReasonCategory.php index d6b802776..72f93e411 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReasonCategory.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityReasonCategory.php @@ -1,35 +1,21 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Entity\ActivityReasonCategory; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\ActivityBundle\Entity\ActivityReasonCategory; + /** - * Description of LoadActivityReasonCategory - * - * @author Champs-Libres Coop + * Description of LoadActivityReasonCategory. */ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtureInterface { @@ -37,27 +23,26 @@ class LoadActivityReasonCategory extends AbstractFixture implements OrderedFixtu { return 16200; } - + public function load(ObjectManager $manager) { $categs = [ - ['name' => - ['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']], - ['name' => - ['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']], + ['name' => ['fr' => 'Logement', 'en' => 'Housing', 'nl' => 'Woning']], + ['name' => ['fr' => 'Démarches chômage', 'en' => 'Unemployment procedure', 'nl' => 'Werkloosheid werkwijze']], ]; - + foreach ($categs as $c) { - print "Creating activity reason category : " . $c['name']['en'] . "\n"; + echo 'Creating activity reason category : ' . $c['name']['en'] . "\n"; $activityReasonCategory = (new ActivityReasonCategory()) ->setName(($c['name'])) ->setActive(true); $manager->persist($activityReasonCategory); $this->addReference( - 'cat_'.$c['name']['en'], - $activityReasonCategory); + 'cat_' . $c['name']['en'], + $activityReasonCategory + ); } - + $manager->flush(); } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php index fa846df68..c2f73c1f8 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivityType.php @@ -1,67 +1,49 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Entity\ActivityType; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\ActivityBundle\Entity\ActivityType; /** - * Description of LoadActivityType - * - * @author Champs-Libres Coop + * Description of LoadActivityType. */ class LoadActivityType extends AbstractFixture implements OrderedFixtureInterface { + public static $references = []; + public function getOrder() { return 16100; } - - public static $references = array(); public function load(ObjectManager $manager) { $types = [ - [ 'name' => - ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']], - [ 'name' => - ['fr' => 'Entretien', 'en' => 'Interview', 'nl' => 'Vraaggesprek']], - [ 'name' => - ['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']] + ['name' => ['fr' => 'Appel téléphonique', 'en' => 'Telephone call', 'nl' => 'Telefoon appel']], + ['name' => ['fr' => 'Entretien', 'en' => 'Interview', 'nl' => 'Vraaggesprek']], + ['name' => ['fr' => 'Inspection', 'en' => 'Inspection', 'nl' => 'Inspectie']], ]; - + foreach ($types as $t) { - print "Creating activity type : " . $t['name']['en'] . "\n"; + echo 'Creating activity type : ' . $t['name']['en'] . "\n"; $activityType = (new ActivityType()) ->setName(($t['name'])); $manager->persist($activityType); - $reference = 'activity_type_'.$t['name']['en']; + $reference = 'activity_type_' . $t['name']['en']; $this->addReference($reference, $activityType); static::$references[] = $reference; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php index 331db2305..a047d3084 100644 --- a/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php +++ b/src/Bundle/ChillActivityBundle/DataFixtures/ORM/LoadActivitytACL.php @@ -1,37 +1,25 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DataFixtures\ORM; +use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\Entity\RoleScope; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; -use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; /** * Add a role CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE for all groups except administrative, - * and a role CHILL_ACTIVITY_SEE for administrative - * - * @author Julien Fastré + * and a role CHILL_ACTIVITY_SEE for administrative. */ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterface { @@ -40,12 +28,12 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac return 16000; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); - foreach (LoadScopes::$references as $scopeRef){ + + foreach (LoadScopes::$references as $scopeRef) { $scope = $this->getReference($scopeRef); //create permission group switch ($permissionsGroup->getName()) { @@ -53,47 +41,49 @@ class LoadActivitytACL extends AbstractFixture implements OrderedFixtureInterfac if ($scope->getName()['en'] === 'administrative') { break 2; // we do not want any power on administrative } + break; + case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], ['administrative', 'social'])) { break 2; // we do not want any power on social or administrative - } + } + break; } - - printf("Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s " - . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); + + printf( + 'Adding CHILL_ACTIVITY_UPDATE & CHILL_ACTIVITY_CREATE & CHILL_ACTIVITY_DELETE, and stats and list permissions to %s ' + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), + $scope->getName()['en'] + ); $roleScopeUpdate = (new RoleScope()) - ->setRole('CHILL_ACTIVITY_UPDATE') - ->setScope($scope); + ->setRole('CHILL_ACTIVITY_UPDATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreate = (new RoleScope()) - ->setRole('CHILL_ACTIVITY_CREATE') - ->setScope($scope); + ->setRole('CHILL_ACTIVITY_CREATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $roleScopeDelete = (new RoleScope()) - ->setRole('CHILL_ACTIVITY_DELETE') - ->setScope($scope); + ->setRole('CHILL_ACTIVITY_DELETE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeDelete); $roleScopeList = (new RoleScope()) - ->setRole(ActivityStatsVoter::LISTS) - ; + ->setRole(ActivityStatsVoter::LISTS); $permissionsGroup->addRoleScope($roleScopeList); $roleScopeStat = (new RoleScope()) - ->setRole(ActivityStatsVoter::STATS) - ; + ->setRole(ActivityStatsVoter::STATS); $permissionsGroup->addRoleScope($roleScopeStat); - + $manager->persist($roleScopeUpdate); $manager->persist($roleScopeCreate); $manager->persist($roleScopeDelete); } - } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php index b43703b67..d11b219e5 100644 --- a/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php +++ b/src/Bundle/ChillActivityBundle/DependencyInjection/ChillActivityExtension.php @@ -1,53 +1,36 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\DependencyInjection; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader; -use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; -use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; +use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** - * This is the class that loads and manages your bundle configuration + * This is the class that loads and manages your bundle configuration. * * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} */ class ChillActivityExtension extends Extension implements PrependExtensionInterface { - /** - * {@inheritdoc} - */ public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - + $container->setParameter('chill_activity.form.time_duration', $config['form']['time_duration']); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/export.yaml'); $loader->load('services/repositories.yaml'); @@ -57,37 +40,37 @@ class ChillActivityExtension extends Extension implements PrependExtensionInterf $loader->load('services/form.yaml'); $loader->load('services/templating.yaml'); } - + public function prepend(ContainerBuilder $container) { $this->prependRoutes($container); $this->prependAuthorization($container); } + public function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + ActivityVoter::UPDATE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::CREATE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::DELETE => [ActivityVoter::SEE_DETAILS], + ActivityVoter::SEE_DETAILS => [ActivityVoter::SEE], + ], + ]); + } + /* (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() */ - public function prependRoutes(ContainerBuilder $container) + public function prependRoutes(ContainerBuilder $container) { //add routes for custom bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillActivityBundle/config/routes.yaml' - ) - ) - )); - } - - public function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - ActivityVoter::UPDATE => array(ActivityVoter::SEE_DETAILS), - ActivityVoter::CREATE => array(ActivityVoter::SEE_DETAILS), - ActivityVoter::DELETE => array(ActivityVoter::SEE_DETAILS), - ActivityVoter::SEE_DETAILS => array(ActivityVoter::SEE) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillActivityBundle/config/routes.yaml', + ], + ], + ]); } } diff --git a/src/Bundle/ChillActivityBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillActivityBundle/DependencyInjection/Configuration.php index 601424ea7..dd23a9b8b 100644 --- a/src/Bundle/ChillActivityBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillActivityBundle/DependencyInjection/Configuration.php @@ -1,71 +1,73 @@ getRootNode('chill_activity'); - + $rootNode - ->children() - ->arrayNode('form') - ->canBeEnabled() - ->children() - ->arrayNode('time_duration') - ->isRequired() - ->requiresAtLeastOneElement() - ->defaultValue( - array( - [ 'label' => '5 minutes', 'seconds' => 300], - [ 'label' => '10 minutes', 'seconds' => 600], - [ 'label' => '15 minutes', 'seconds' => 900], - [ 'label' => '20 minutes', 'seconds' => 1200], - [ 'label' => '25 minutes', 'seconds' => 1500], - [ 'label' => '30 minutes', 'seconds' => 1800], - [ 'label' => '45 minutes', 'seconds' => 2700], - [ 'label' => '1 hour', 'seconds' => 3600], - [ 'label' => '1 hour 15', 'seconds' => 4500], - [ 'label' => '1 hour 30', 'seconds' => 5400], - [ 'label' => '1 hour 45', 'seconds' => 6300], - [ 'label' => '2 hours', 'seconds' => 7200], - ) - ) - ->info('The intervals of time to show in activity form') - - ->prototype('array') - ->children() - ->scalarNode('seconds') - ->info("The number of seconds of this duration. Must be an integer.") - ->cannotBeEmpty() - ->validate() - ->ifTrue(function($data) { - return !is_int($data); - })->thenInvalid("The value %s is not a valid integer") - ->end() - ->end() - ->scalarNode('label') - ->cannotBeEmpty() - ->info("The label to show into fields") - ->end() - ->end() - - ->end() + ->children() + ->arrayNode('form') + ->canBeEnabled() + ->children() + ->arrayNode('time_duration') + ->isRequired() + ->requiresAtLeastOneElement() + ->defaultValue( + [ + ['label' => '5 minutes', 'seconds' => 300], + ['label' => '10 minutes', 'seconds' => 600], + ['label' => '15 minutes', 'seconds' => 900], + ['label' => '20 minutes', 'seconds' => 1200], + ['label' => '25 minutes', 'seconds' => 1500], + ['label' => '30 minutes', 'seconds' => 1800], + ['label' => '45 minutes', 'seconds' => 2700], + ['label' => '1 hour', 'seconds' => 3600], + ['label' => '1 hour 15', 'seconds' => 4500], + ['label' => '1 hour 30', 'seconds' => 5400], + ['label' => '1 hour 45', 'seconds' => 6300], + ['label' => '2 hours', 'seconds' => 7200], + ] + ) + ->info('The intervals of time to show in activity form') + ->prototype('array') + ->children() + ->scalarNode('seconds') + ->info('The number of seconds of this duration. Must be an integer.') + ->cannotBeEmpty() + ->validate() + ->ifTrue(function ($data) { + return !is_int($data); + })->thenInvalid('The value %s is not a valid integer') + ->end() + ->end() + ->scalarNode('label') + ->cannotBeEmpty() + ->info('The label to show into fields') + ->end() + ->end() + ->end() // ->validate() -// +// // ->ifTrue(function ($data) { // // test this is an array // if (!is_array($data)) { @@ -84,11 +86,10 @@ class Configuration implements ConfigurationInterface // }) // ->thenInvalid("The data are invalid. The keys must be a string and the value integers") // ->end() - ->end() - ->end() - - ->end() - ->end(); + ->end() + ->end() + ->end() + ->end(); return $treeBuilder; } diff --git a/src/Bundle/ChillActivityBundle/Entity/Activity.php b/src/Bundle/ChillActivityBundle/Entity/Activity.php index e96db03db..29d30f0bb 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -1,55 +1,65 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Entity; -use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; -use Doctrine\ORM\Mapping as ORM; -use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Center; -use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\ActivityBundle\Entity\ActivityType; -use Chill\PersonBundle\Entity\Person; +use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; -use Doctrine\Common\Collections\Collection; -use Doctrine\Common\Collections\ArrayCollection; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Validator\Constraints\Entity\UserCircleConsistency; +use Chill\PersonBundle\Entity\Person; +use DateTime; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * Class Activity + * Class Activity. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activity") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks * @UserCircleConsistency( - * "CHILL_ACTIVITY_SEE_DETAILS", - * getUserFunction="getUser", - * path="scope") + * "CHILL_ACTIVITY_SEE_DETAILS", + * getUserFunction="getUser", + * path="scope") */ class Activity implements HasCenterInterface, HasScopeInterface { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $attendee; + + /** + * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") + */ + private $comment; + + /** + * @var DateTime + * @ORM\Column(type="datetime") + */ + private $date; + + /** + * @var DateTime + * @ORM\Column(type="time") + */ + private $durationTime; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -58,28 +68,10 @@ class Activity implements HasCenterInterface, HasScopeInterface private $id; /** - * @var User - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") + * @var Person + * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") */ - private $user; - - /** - * @var \DateTime - * @ORM\Column(type="datetime") - */ - private $date; - - /** - * @var \DateTime - * @ORM\Column(type="time") - */ - private $durationTime; - - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $attendee; + private $person; /** * @var ActivityReason @@ -87,12 +79,6 @@ class Activity implements HasCenterInterface, HasScopeInterface */ private $reasons; - /** - * @var ActivityType - * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType") - */ - private $type; - /** * @var Scope * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") @@ -100,15 +86,16 @@ class Activity implements HasCenterInterface, HasScopeInterface private $scope; /** - * @var Person - * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") + * @var ActivityType + * @ORM\ManyToOne(targetEntity="Chill\ActivityBundle\Entity\ActivityType") */ - private $person; + private $type; /** - * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\CommentEmbeddable", columnPrefix="comment_") + * @var User + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") */ - private $comment; + private $user; /** * Activity constructor. @@ -120,111 +107,8 @@ class Activity implements HasCenterInterface, HasScopeInterface } /** - * Get id + * Add a reason. * - * @return integer - */ - public function getId() - { - return $this->id; - } - - /** - * Set user - * - * @param User $user - * @return Activity - */ - public function setUser(User $user) - { - $this->user = $user; - - return $this; - } - - /** - * Get user - * - * @return User - */ - public function getUser() - { - return $this->user; - } - - /** - * Set date - * - * @param \DateTime $date - * @return Activity - */ - public function setDate($date) - { - $this->date = $date; - - return $this; - } - - /** - * Get date - * - * @return \DateTime - */ - public function getDate() - { - return $this->date; - } - - /** - * Set durationTime - * - * @param \DateTime $durationTime - * @return Activity - */ - public function setDurationTime($durationTime) - { - $this->durationTime = $durationTime; - - return $this; - } - - /** - * Get durationTime - * - * @return \DateTime - */ - public function getDurationTime() - { - return $this->durationTime; - } - - /** - * Set attendee - * - * @param boolean $attendee - * @return Activity - */ - public function setAttendee($attendee) - { - $this->attendee = $attendee; - - return $this; - } - - /** - * Get attendee - * - * @return boolean - */ - public function getAttendee() - { - return $this->attendee; - } - - /** - * Add a reason - * - * @param ActivityReason $reason * @return Activity */ public function addReason(ActivityReason $reason) @@ -235,95 +119,18 @@ class Activity implements HasCenterInterface, HasScopeInterface } /** - * @param ActivityReason $reason - */ - public function removeReason(ActivityReason $reason) - { - $this->reasons->removeElement($reason); - } - - /** - * Get reasons + * Get attendee. * - * @return Collection + * @return bool */ - public function getReasons() + public function getAttendee() { - return $this->reasons; - } - - /** - * Set type - * - * @param ActivityType $type - * @return Activity - */ - public function setType(ActivityType $type) - { - $this->type = $type; - - return $this; - } - - /** - * Get type - * - * @return ActivityType - */ - public function getType() - { - return $this->type; - } - - /** - * Set scope - * - * @param Scope $scope - * @return Activity - */ - public function setScope(Scope $scope) - { - $this->scope = $scope; - - return $this; - } - - /** - * Get scope - * - * @return Scope - */ - public function getScope() - { - return $this->scope; - } - - /** - * Set person - * - * @param Person $person - * @return Activity - */ - public function setPerson(Person $person) - { - $this->person = $person; - - return $this; - } - - /** - * Get person - * - * @return Person - */ - public function getPerson() - { - return $this->person; + return $this->attendee; } /** * get the center - * center is extracted from person + * center is extracted from person. * * @return Center */ @@ -340,6 +147,105 @@ class Activity implements HasCenterInterface, HasScopeInterface return $this->comment; } + /** + * Get date. + * + * @return DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * Get durationTime. + * + * @return DateTime + */ + public function getDurationTime() + { + return $this->durationTime; + } + + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get person. + * + * @return Person + */ + public function getPerson() + { + return $this->person; + } + + /** + * Get reasons. + * + * @return Collection + */ + public function getReasons() + { + return $this->reasons; + } + + /** + * Get scope. + * + * @return Scope + */ + public function getScope() + { + return $this->scope; + } + + /** + * Get type. + * + * @return ActivityType + */ + public function getType() + { + return $this->type; + } + + /** + * Get user. + * + * @return User + */ + public function getUser() + { + return $this->user; + } + + public function removeReason(ActivityReason $reason) + { + $this->reasons->removeElement($reason); + } + + /** + * Set attendee. + * + * @param bool $attendee + * + * @return Activity + */ + public function setAttendee($attendee) + { + $this->attendee = $attendee; + + return $this; + } + /** * @param \Chill\MainBundle\Entity\Embeddalbe\CommentEmbeddable $comment */ @@ -347,5 +253,80 @@ class Activity implements HasCenterInterface, HasScopeInterface { $this->comment = $comment; } -} + /** + * Set date. + * + * @param DateTime $date + * + * @return Activity + */ + public function setDate($date) + { + $this->date = $date; + + return $this; + } + + /** + * Set durationTime. + * + * @param DateTime $durationTime + * + * @return Activity + */ + public function setDurationTime($durationTime) + { + $this->durationTime = $durationTime; + + return $this; + } + + /** + * Set person. + * + * @return Activity + */ + public function setPerson(Person $person) + { + $this->person = $person; + + return $this; + } + + /** + * Set scope. + * + * @return Activity + */ + public function setScope(Scope $scope) + { + $this->scope = $scope; + + return $this; + } + + /** + * Set type. + * + * @return Activity + */ + public function setType(ActivityType $type) + { + $this->type = $type; + + return $this; + } + + /** + * Set user. + * + * @return Activity + */ + public function setUser(User $user) + { + $this->user = $user; + + return $this; + } +} diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php b/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php index 6116815dc..0a25c4da0 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityReason.php @@ -1,40 +1,41 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use Chill\ActivityBundle\Entity\ActivityReasonCategory; /** - * Class ActivityReason + * Class ActivityReason. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activityreason") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class ActivityReason { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * @var ActivityReasonCategory + * @ORM\ManyToOne( + * targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory", + * inversedBy="reasons") + */ + private $category; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -49,86 +50,17 @@ class ActivityReason private $name; /** - * @var ActivityReasonCategory - * @ORM\ManyToOne( - * targetEntity="Chill\ActivityBundle\Entity\ActivityReasonCategory", - * inversedBy="reasons") - */ - private $category; - - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active = true; - - - /** - * Get id + * Get active. * - * @return integer + * @return bool */ - public function getId() + public function getActive() { - return $this->id; + return $this->active; } /** - * Set name - * - * @param array $name - * @return ActivityReason - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name - * - * @return array | string - */ - public function getName($locale = null) - { - if ($locale) { - if (isset($this->name[$locale])) { - return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } - } - } - return ''; - } else { - return $this->name; - } - } - - /** - * Set category of the reason. If you set to the reason an inactive - * category, the reason will become inactive - * - * @param ActivityReasonCategory $category - * @return ActivityReason - */ - public function setCategory(ActivityReasonCategory $category) - { - if($this->category !== $category && ! $category->getActive()) { - $this->setActive(False); - } - - $this->category = $category; - - return $this; - } - - /** - * Get category + * Get category. * * @return ActivityReasonCategory */ @@ -138,9 +70,46 @@ class ActivityReason } /** - * Set active + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get name. + * + * @param mixed|null $locale + * + * @return array | string + */ + public function getName($locale = null) + { + if ($locale) { + if (isset($this->name[$locale])) { + return $this->name[$locale]; + } + + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; + } + } + + return ''; + } + + return $this->name; + } + + /** + * Set active. + * + * @param bool $active * - * @param boolean $active * @return ActivityReason */ public function setActive($active) @@ -151,13 +120,33 @@ class ActivityReason } /** - * Get active + * Set category of the reason. If you set to the reason an inactive + * category, the reason will become inactive. * - * @return boolean + * @return ActivityReason */ - public function getActive() + public function setCategory(ActivityReasonCategory $category) { - return $this->active; + if ($this->category !== $category && !$category->getActive()) { + $this->setActive(false); + } + + $this->category = $category; + + return $this; + } + + /** + * Set name. + * + * @param array $name + * + * @return ActivityReason + */ + public function setName($name) + { + $this->name = $name; + + return $this; } } - diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php b/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php index dc5d5f9ba..4d19d77f7 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityReasonCategory.php @@ -1,39 +1,34 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Entity; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\ORM\Mapping as ORM; /** - * Class ActivityReasonCategory + * Class ActivityReasonCategory. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activityreasoncategory") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class ActivityReasonCategory { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -48,20 +43,15 @@ class ActivityReasonCategory private $name; /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active = true; - - /** - * Array of ActivityReason + * Array of ActivityReason. + * * @var ArrayCollection * @ORM\OneToMany( * targetEntity="Chill\ActivityBundle\Entity\ActivityReason", - * mappedBy="category") + * mappedBy="category") */ private $reasons; - + /** * ActivityReasonCategory constructor. */ @@ -69,19 +59,29 @@ class ActivityReasonCategory { $this->reasons = new ArrayCollection(); } - + /** * @return string */ public function __toString() { - return 'ActivityReasonCategory('.$this->getName('x').')'; + return 'ActivityReasonCategory(' . $this->getName('x') . ')'; } /** - * Get id + * Get active. * - * @return integer + * @return bool + */ + public function getActive() + { + return $this->active; + } + + /** + * Get id. + * + * @return int */ public function getId() { @@ -89,20 +89,9 @@ class ActivityReasonCategory } /** - * Set name + * Get name. * - * @param array $name - * @return ActivityReasonCategory - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name + * @param mixed|null $locale * * @return array */ @@ -111,48 +100,53 @@ class ActivityReasonCategory if ($locale) { if (isset($this->name[$locale])) { return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } + } + + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; } } + return ''; - } else { - return $this->name; } + + return $this->name; } /** * Declare a category as active (or not). When a category is set * as unactive, all the reason have this entity as category is also - * set as unactive + * set as unactive. + * + * @param bool $active * - * @param boolean $active * @return ActivityReasonCategory */ public function setActive($active) { - if($this->active !== $active && !$active) { + if ($this->active !== $active && !$active) { foreach ($this->reasons as $reason) { $reason->setActive($active); } } - + $this->active = $active; - + return $this; } /** - * Get active + * Set name. * - * @return boolean + * @param array $name + * + * @return ActivityReasonCategory */ - public function getActive() + public function setName($name) { - return $this->active; + $this->name = $name; + + return $this; } } - diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index 25854d385..81646282f 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -1,21 +1,10 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Entity; @@ -23,17 +12,22 @@ namespace Chill\ActivityBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Class ActivityType + * Class ActivityType. * - * @package Chill\ActivityBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="activitytype") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class ActivityType { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -46,18 +40,22 @@ class ActivityType * @ORM\Column(type="json_array") */ private $name; - - /** - * @var bool - * @ORM\Column(type="boolean") - */ - private $active = true; - /** - * Get id + * Get active + * return true if the type is active. * - * @return integer + * @return bool + */ + public function getActive() + { + return $this->active; + } + + /** + * Get id. + * + * @return int */ public function getId() { @@ -65,20 +63,9 @@ class ActivityType } /** - * Set name + * Get name. * - * @param array $name - * @return ActivityType - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name + * @param mixed|null $locale * * @return array | string */ @@ -87,50 +74,57 @@ class ActivityType if ($locale) { if (isset($this->name[$locale])) { return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } + } + + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; } } + return ''; - } else { - return $this->name; } + + return $this->name; } - - /** - * Get active - * return true if the type is active. - * - * @return boolean - */ - public function getActive() { - return $this->active; - } - + /** * Is active - * return true if the type is active - * - * @return boolean + * return true if the type is active. + * + * @return bool */ - public function isActive() { + public function isActive() + { return $this->getActive(); } /** * Set active - * set to true if the type is active - * - * @param boolean $active + * set to true if the type is active. + * + * @param bool $active + * * @return ActivityType */ - public function setActive($active) { + public function setActive($active) + { $this->active = $active; + return $this; } -} + /** + * Set name. + * + * @param array $name + * + * @return ActivityType + */ + public function setName($name) + { + $this->name = $name; + return $this; + } +} diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php index 6614caace..daa2b8b1e 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityReasonAggregator.php @@ -1,107 +1,96 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Aggregator; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query\Expr\Join; +use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr\Join; +use Doctrine\ORM\QueryBuilder; +use RuntimeException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - * @author Julien Fastré - */ -class ActivityReasonAggregator implements AggregatorInterface, +class ActivityReasonAggregator implements + AggregatorInterface, ExportElementValidatedInterface { /** - * * @var EntityRepository */ protected $categoryRepository; /** - * * @var EntityRepository */ protected $reasonRepository; /** - * * @var TranslatableStringHelper */ protected $stringHelper; public function __construct( - EntityRepository $categoryRepository, - EntityRepository $reasonRepository, - TranslatableStringHelper $stringHelper + EntityRepository $categoryRepository, + EntityRepository $reasonRepository, + TranslatableStringHelper $stringHelper ) { $this->categoryRepository = $categoryRepository; - $this->reasonRepository = $reasonRepository; - $this->stringHelper = $stringHelper; + $this->reasonRepository = $reasonRepository; + $this->stringHelper = $stringHelper; + } + + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); } public function alterQuery(QueryBuilder $qb, $data) { // add select element - if ($data['level'] === 'reasons') { + if ('reasons' === $data['level']) { $elem = 'reasons.id'; $alias = 'activity_reasons_id'; - } elseif ($data['level'] === 'categories') { + } elseif ('categories' === $data['level']) { $elem = 'category.id'; $alias = 'activity_categories_id'; } else { - throw new \RuntimeException('the data provided are not recognized'); + throw new RuntimeException('the data provided are not recognized'); } - $qb->addSelect($elem.' as '.$alias); + $qb->addSelect($elem . ' as ' . $alias); // make a jointure only if needed $join = $qb->getDQLPart('join'); + if ( - (array_key_exists('activity', $join) - && - !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') + ( + array_key_exists('activity', $join) + && !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') ) - OR - (! array_key_exists('activity', $join)) + or (!array_key_exists('activity', $join)) ) { $qb->add( - 'join', - array('activity' => - new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons') - ), - true); + 'join', + ['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons'), + ], + true + ); } // join category if necessary - if ($alias === 'activity_categories_id') { + if ('activity_categories_id' === $alias) { // add join only if needed if (!$this->checkJoinAlreadyDefined($qb->getDQLPart('join')['activity'], 'category')) { $qb->join('reasons.category', 'category'); @@ -118,12 +107,109 @@ class ActivityReasonAggregator implements AggregatorInterface, } } + public function applyOn() + { + return 'activity'; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('level', ChoiceType::class, [ + 'choices' => [ + 'By reason' => 'reasons', + 'By category of reason' => 'categories', + ], + 'multiple' => false, + 'expanded' => true, + 'label' => 'Reason\'s level', + ]); + } + + public function getLabels($key, array $values, $data) + { + // for performance reason, we load data from db only once + switch ($data['level']) { + case 'reasons': + $this->reasonRepository->findBy(['id' => $values]); + + break; + + case 'categories': + $this->categoryRepository->findBy(['id' => $values]); + + break; + + default: + throw new RuntimeException(sprintf( + "the level data '%s' is invalid", + $data['level'] + )); + } + + return function ($value) use ($data) { + if ('_header' === $value) { + return 'reasons' === $data['level'] ? + 'Group by reasons' + : + 'Group by categories of reason'; + } + + switch ($data['level']) { + case 'reasons': + /* @var $r \Chill\ActivityBundle\Entity\ActivityReason */ + $r = $this->reasonRepository->find($value); + + return $this->stringHelper->localize($r->getCategory()->getName()) + . ' > ' + . $this->stringHelper->localize($r->getName()); + + break; + + case 'categories': + $c = $this->categoryRepository->find($value); + + return $this->stringHelper->localize($c->getName()); + + break; + // no need for a default : the default was already set above + } + }; + } + + public function getQueryKeys($data) + { + // add select element + if ('reasons' === $data['level']) { + return ['activity_reasons_id']; + } + + if ('categories' === $data['level']) { + return ['activity_categories_id']; + } + + throw new RuntimeException('the data provided are not recognised'); + } + + public function getTitle() + { + return 'Aggregate by activity reason'; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['level']) { + $context->buildViolation("The reasons's level should not be empty") + ->addViolation(); + } + } + /** - * Check if a join between Activity and another alias + * Check if a join between Activity and another alias. * * @param Join[] $joins * @param string $alias the alias to search for - * @return boolean + * + * @return bool */ private function checkJoinAlreadyDefined(array $joins, $alias) { @@ -135,99 +221,4 @@ class ActivityReasonAggregator implements AggregatorInterface, return false; } - - public function applyOn() - { - return 'activity'; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('level', ChoiceType::class, array( - 'choices' => array( - 'By reason' => 'reasons', - 'By category of reason' => 'categories' - ), - 'multiple' => false, - 'expanded' => true, - 'label' => 'Reason\'s level' - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['level'] === null) { - $context->buildViolation("The reasons's level should not be empty") - ->addViolation(); - } - } - - public function getTitle() - { - return "Aggregate by activity reason"; - } - - public function addRole() - { - return new Role(ActivityStatsVoter::STATS); - } - - public function getLabels($key, array $values, $data) - { - // for performance reason, we load data from db only once - switch ($data['level']) { - case 'reasons': - $this->reasonRepository->findBy(array('id' => $values)); - break; - case 'categories': - $this->categoryRepository->findBy(array('id' => $values)); - break; - default: - throw new \RuntimeException(sprintf("the level data '%s' is invalid", - $data['level'])); - } - - return function($value) use ($data) { - if ($value === '_header') { - return $data['level'] === 'reasons' ? - 'Group by reasons' - : - 'Group by categories of reason' - ; - } - - switch ($data['level']) { - case 'reasons': - /* @var $r \Chill\ActivityBundle\Entity\ActivityReason */ - $r = $this->reasonRepository->find($value); - - return $this->stringHelper->localize($r->getCategory()->getName()) - ." > " - . $this->stringHelper->localize($r->getName()); - ; - break; - case 'categories': - $c = $this->categoryRepository->find($value); - - return $this->stringHelper->localize($c->getName()); - break; - // no need for a default : the default was already set above - } - }; - - } - - public function getQueryKeys($data) - { - // add select element - if ($data['level'] === 'reasons') { - return array('activity_reasons_id'); - } elseif ($data['level'] === 'categories') { - return array ('activity_categories_id'); - } else { - throw new \RuntimeException('the data provided are not recognised'); - } - - } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php index 3dec544ba..a50088384 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityTypeAggregator.php @@ -1,89 +1,58 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Aggregator; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; +use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\Expr\Join; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class ActivityTypeAggregator implements AggregatorInterface { - + public const KEY = 'activity_type_aggregator'; + /** - * - * @var EntityRepository - */ - protected $typeRepository; - - /** - * * @var TranslatableStringHelper */ protected $stringHelper; - - const KEY = 'activity_type_aggregator'; - + + /** + * @var EntityRepository + */ + protected $typeRepository; + public function __construct( - EntityRepository $typeRepository, - TranslatableStringHelper $stringHelper + EntityRepository $typeRepository, + TranslatableStringHelper $stringHelper ) { - $this->typeRepository = $typeRepository; - $this->stringHelper = $stringHelper; + $this->typeRepository = $typeRepository; + $this->stringHelper = $stringHelper; } - + + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + public function alterQuery(QueryBuilder $qb, $data) { - // add select element + // add select element $qb->addSelect(sprintf('IDENTITY(activity.type) AS %s', self::KEY)); - + // add the "group by" part $groupBy = $qb->addGroupBy(self::KEY); } - - /** - * Check if a join between Activity and another alias - * - * @param Join[] $joins - * @param string $alias the alias to search for - * @return boolean - */ - private function checkJoinAlreadyDefined(array $joins, $alias) - { - foreach ($joins as $join) { - if ($join->getAlias() === $alias) { - return true; - } - } - - return false; - } public function applyOn() { @@ -95,23 +64,13 @@ class ActivityTypeAggregator implements AggregatorInterface // no form required for this aggregator } - public function getTitle() - { - return "Aggregate by activity type"; - } - - public function addRole() - { - return new Role(ActivityStatsVoter::STATS); - } - public function getLabels($key, array $values, $data) { // for performance reason, we load data from db only once - $this->typeRepository->findBy(array('id' => $values)); - - return function($value) use ($data) { - if ($value === '_header') { + $this->typeRepository->findBy(['id' => $values]); + + return function ($value) { + if ('_header' === $value) { return 'Activity type'; } @@ -120,12 +79,34 @@ class ActivityTypeAggregator implements AggregatorInterface return $this->stringHelper->localize($t->getName()); }; - } public function getQueryKeys($data) { - return array(self::KEY); + return [self::KEY]; } + public function getTitle() + { + return 'Aggregate by activity type'; + } + + /** + * Check if a join between Activity and another alias. + * + * @param Join[] $joins + * @param string $alias the alias to search for + * + * @return bool + */ + private function checkJoinAlreadyDefined(array $joins, $alias) + { + foreach ($joins as $join) { + if ($join->getAlias() === $alias) { + return true; + } + } + + return false; + } } diff --git a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php index ca01e0ae5..ee04a2419 100644 --- a/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php +++ b/src/Bundle/ChillActivityBundle/Export/Aggregator/ActivityUserAggregator.php @@ -1,51 +1,37 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\ActivityBundle\Export\Aggregator; - -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Query\Expr\Join; -use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityManagerInterface; -use Chill\MainBundle\Entity\User; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\ActivityBundle\Export\Aggregator; + +use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Export\AggregatorInterface; +use Closure; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; + class ActivityUserAggregator implements AggregatorInterface { + public const KEY = 'activity_user_id'; + /** - * * @var EntityManagerInterface */ protected $em; - - const KEY = 'activity_user_id'; - - function __construct(EntityManagerInterface $em) + + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - + public function addRole() { return new Role(ActivityStatsVoter::STATS); @@ -53,9 +39,9 @@ class ActivityUserAggregator implements AggregatorInterface public function alterQuery(QueryBuilder $qb, $data) { - // add select element + // add select element $qb->addSelect(sprintf('IDENTITY(activity.user) AS %s', self::KEY)); - + // add the "group by" part $qb->addGroupBy(self::KEY); } @@ -70,16 +56,17 @@ class ActivityUserAggregator implements AggregatorInterface // nothing to add } - public function getLabels($key, $values, $data): \Closure + public function getLabels($key, $values, $data): Closure { // preload users at once $this->em->getRepository(User::class) ->findBy(['id' => $values]); - - return function($value) { + + return function ($value) { switch ($value) { case '_header': return 'activity user'; + default: return $this->em->getRepository(User::class)->find($value) ->getUsername(); @@ -89,11 +76,11 @@ class ActivityUserAggregator implements AggregatorInterface public function getQueryKeys($data) { - return [ self::KEY ]; + return [self::KEY]; } public function getTitle(): string { - return "Aggregate by activity user"; + return 'Aggregate by activity user'; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php index 3498d7a13..449d6fc10 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/CountActivity.php @@ -1,121 +1,65 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Export; -use Chill\MainBundle\Export\ExportInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Query; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\MainBundle\Export\ExportInterface; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use LogicException; +use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class CountActivity implements ExportInterface { /** - * * @var EntityManagerInterface */ protected $entityManager; - + public function __construct( - EntityManagerInterface $em - ) - { + EntityManagerInterface $em + ) { $this->entityManager = $em; } - + public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - - } - - public function getDescription() - { - return "Count activities by various parameters."; - } - - public function getTitle() - { - return "Count activities"; - } - - public function getType() - { - return 'activity'; - } - - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) - { - $qb = $this->entityManager->createQueryBuilder(); - $centers = array_map(function($el) { return $el['center']; }, $acl); - - $qb->select('COUNT(activity.id) as export_count_activity') - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ; - - $qb->where($qb->expr()->in('person.center', ':centers')) - ->setParameter('centers', $centers) - ; - - return $qb; - } - - public function supportsModifiers() - { - return array('person', 'activity'); - } - - public function requiredRole() - { - return new Role(ActivityStatsVoter::STATS); } public function getAllowedFormattersTypes() { - return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); + return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription() + { + return 'Count activities by various parameters.'; } public function getLabels($key, array $values, $data) { - if ($key !== 'export_count_activity') { - throw new \LogicException("the key $key is not used by this export"); + if ('export_count_activity' !== $key) { + throw new LogicException("the key {$key} is not used by this export"); } - - return function($value) { - return $value === '_header' ? + + return function ($value) { + return '_header' === $value ? 'Number of activities' : - $value - ; + $value; }; } public function getQueryKeys($data) { - return array('export_count_activity'); + return ['export_count_activity']; } public function getResult($qb, $data) @@ -123,4 +67,40 @@ class CountActivity implements ExportInterface return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } + public function getTitle() + { + return 'Count activities'; + } + + public function getType() + { + return 'activity'; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $qb = $this->entityManager->createQueryBuilder(); + $centers = array_map(function ($el) { + return $el['center']; + }, $acl); + + $qb->select('COUNT(activity.id) as export_count_activity') + ->from('ChillActivityBundle:Activity', 'activity') + ->join('activity.person', 'person'); + + $qb->where($qb->expr()->in('person.center', ':centers')) + ->setParameter('centers', $centers); + + return $qb; + } + + public function requiredRole() + { + return new Role(ActivityStatsVoter::STATS); + } + + public function supportsModifiers() + { + return ['person', 'activity']; + } } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php index 6e5d7b0b8..4e0d3b367 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/ListActivity.php @@ -1,69 +1,42 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Export; -use Chill\MainBundle\Export\ListInterface; use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Scope; -use Chill\ActivityBundle\Entity\ActivityType; -use Doctrine\ORM\Query\Expr; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Symfony\Component\Form\FormBuilderInterface; +use Chill\MainBundle\Export\FormatterInterface; +use Chill\MainBundle\Export\ListInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use DateTime; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Constraints\Callback; -use Doctrine\ORM\Query; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Validator\Context\ExecutionContextInterface; +use function array_key_exists; + /** - * Create a list for all activities - * - * @author Julien Fastré + * Create a list for all activities. */ class ListActivity implements ListInterface { - /** - * * @var EntityManagerInterface */ protected $entityManager; - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - protected $fields = array( + protected $fields = [ 'id', 'date', 'durationTime', @@ -74,115 +47,131 @@ class ListActivity implements ListInterface 'type_name', 'person_firstname', 'person_lastname', - 'person_id' - ); + 'person_id', + ]; + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * @var TranslatorInterface + */ + protected $translator; public function __construct( - EntityManagerInterface $em, - TranslatorInterface $translator, - TranslatableStringHelper $translatableStringHelper - ) - { + EntityManagerInterface $em, + TranslatorInterface $translator, + TranslatableStringHelper $translatableStringHelper + ) { $this->entityManager = $em; $this->translator = $translator; $this->translatableStringHelper = $translatableStringHelper; } - /** - * {@inheritDoc} - * - * @param FormBuilderInterface $builder - */ public function buildForm(FormBuilderInterface $builder) { - $builder->add('fields', ChoiceType::class, array( + $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, 'choices' => array_combine($this->fields, $this->fields), - 'label' => 'Fields to include in export', - 'constraints' => [new Callback(array( - 'callback' => function($selected, ExecutionContextInterface $context) { + 'label' => 'Fields to include in export', + 'constraints' => [new Callback([ + 'callback' => function ($selected, ExecutionContextInterface $context) { if (count($selected) === 0) { $context->buildViolation('You must select at least one element') ->atPath('fields') ->addViolation(); } - } - ))] - )); - + }, + ])], + ]); } /** - * {@inheritDoc} - * * @return type */ public function getAllowedFormattersTypes() { - return array(FormatterInterface::TYPE_LIST); + return [FormatterInterface::TYPE_LIST]; } public function getDescription() { - return "List activities"; + return 'List activities'; } public function getLabels($key, array $values, $data) { - switch ($key) - { - case 'date' : - return function($value) { - if ($value === '_header') return 'date'; + switch ($key) { + case 'date': + return function ($value) { + if ('_header' === $value) { + 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'); }; + case 'attendee': - return function($value) { - if ($value === '_header') return 'attendee'; + return function ($value) { + if ('_header' === $value) { + return 'attendee'; + } return $value ? 1 : 0; }; - case 'list_reasons' : + + case 'list_reasons': /* @var $activityReasonsRepository EntityRepository */ $activityRepository = $this->entityManager ->getRepository('ChillActivityBundle:Activity'); - return function($value) use ($activityRepository) { - if ($value === '_header') return 'activity reasons'; + return function ($value) use ($activityRepository) { + if ('_header' === $value) { + return 'activity reasons'; + } $activity = $activityRepository - ->find($value); + ->find($value); - return implode(", ", array_map(function(ActivityReason $r) { - - return '"'. + return implode(', ', array_map(function (ActivityReason $r) { + return '"' . $this->translatableStringHelper->localize($r->getCategory()->getName()) - .' > '. + . ' > ' . $this->translatableStringHelper->localize($r->getName()) - .'"'; + . '"'; }, $activity->getReasons()->toArray())); }; - case 'circle_name' : - return function($value) { - if ($value === '_header') return 'circle'; + + case 'circle_name': + return function ($value) { + if ('_header' === $value) { + return 'circle'; + } return $this->translatableStringHelper - ->localize(json_decode($value, true)); + ->localize(json_decode($value, true)); }; - case 'type_name' : - return function($value) { - if ($value === '_header') return 'activity type'; + + case 'type_name': + return function ($value) { + if ('_header' === $value) { + return 'activity type'; + } return $this->translatableStringHelper - ->localize(json_decode($value, true)); + ->localize(json_decode($value, true)); }; + default: - return function($value) use ($key) { - if ($value === '_header') return $key; + return function ($value) use ($key) { + if ('_header' === $value) { + return $key; + } return $value; }; @@ -209,68 +198,83 @@ class ListActivity implements ListInterface return 'activity'; } - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) { - $centers = array_map(function($el) { return $el['center']; }, $acl); + $centers = array_map(function ($el) { + return $el['center']; + }, $acl); // throw an error if any fields are present - if (!\array_key_exists('fields', $data)) { - throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " - . "have been checked"); + if (!array_key_exists('fields', $data)) { + throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields ' + . 'have been checked'); } $qb = $this->entityManager->createQueryBuilder(); $qb - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center') - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - ; + ->from('ChillActivityBundle:Activity', 'activity') + ->join('activity.person', 'person') + ->join('person.center', 'center') + ->andWhere('center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); foreach ($this->fields as $f) { if (in_array($f, $data['fields'])) { switch ($f) { case 'id': $qb->addSelect('activity.id AS id'); + break; + case 'person_firstname': $qb->addSelect('person.firstName AS person_firstname'); + break; + case 'person_lastname': $qb->addSelect('person.lastName AS person_lastname'); + break; + case 'person_id': $qb->addSelect('person.id AS person_id'); + break; + case 'user_username': $qb->join('activity.user', 'user'); $qb->addSelect('user.username AS user_username'); + break; + case 'circle_name': $qb->join('activity.scope', 'circle'); $qb->addSelect('circle.name AS circle_name'); + break; + case 'type_name': $qb->join('activity.type', 'type'); $qb->addSelect('type.name AS type_name'); + break; + case 'list_reasons': // this is a trick... The reasons is filled with the // activity id which will be used to load reasons $qb->addSelect('activity.id AS list_reasons'); + break; + default: $qb->addSelect(sprintf('activity.%s as %s', $f, $f)); + break; } - } } - - return $qb; } @@ -281,7 +285,6 @@ class ListActivity implements ListInterface public function supportsModifiers() { - return array('activity', 'person'); + return ['activity', 'person']; } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php index 8fd4ec00b..bed3e9dd5 100644 --- a/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php +++ b/src/Bundle/ChillActivityBundle/Export/Export/StatActivityDuration.php @@ -1,154 +1,93 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Export; -use Chill\MainBundle\Export\ExportInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Query; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\MainBundle\Export\ExportInterface; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use LogicException; +use Symfony\Component\Security\Core\Role\Role; /** * This export allow to compute stats on activity duration. - * + * * The desired stat must be given in constructor. - * - * - * @author Julien Fastré */ class StatActivityDuration implements ExportInterface { - /** - * - * @var EntityManagerInterface - */ - protected $entityManager; - - const SUM = 'sum'; - + public const SUM = 'sum'; + /** * The action for this report. * * @var string */ protected $action; - + /** - * constructor - * - * @param EntityManagerInterface $em + * @var EntityManagerInterface + */ + protected $entityManager; + + /** + * constructor. + * * @param string $action the stat to perform */ public function __construct( - EntityManagerInterface $em, - $action = 'sum' - ) - { + EntityManagerInterface $em, + $action = 'sum' + ) { $this->entityManager = $em; $this->action = $action; } - + public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - - } - - public function getDescription() - { - if ($this->action === self::SUM) { - return "Sum activities duration by various parameters."; - } - } - - public function getTitle() - { - if ($this->action === self::SUM) { - return "Sum activity duration"; - } - - } - - public function getType() - { - return 'activity'; - } - - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) - { - $centers = array_map(function($el) { return $el['center']; }, $acl); - $qb = $this->entityManager->createQueryBuilder(); - - if ($this->action === self::SUM) { - $select = "SUM(activity.durationTime) AS export_stat_activity"; - } - - $qb->select($select) - ->from('ChillActivityBundle:Activity', 'activity') - ->join('activity.person', 'person') - ->join('person.center', 'center') - ->where($qb->expr()->in('center', ':centers')) - ->setParameter(':centers', $centers) - ; - - return $qb; - } - - public function supportsModifiers() - { - return array('person', 'activity'); - } - - public function requiredRole() - { - return new Role(ActivityStatsVoter::STATS); } public function getAllowedFormattersTypes() { - return array(\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR); + return [\Chill\MainBundle\Export\FormatterInterface::TYPE_TABULAR]; + } + + public function getDescription() + { + if (self::SUM === $this->action) { + return 'Sum activities duration by various parameters.'; + } } public function getLabels($key, array $values, $data) { - if ($key !== 'export_stat_activity') { - throw new \LogicException("the key $key is not used by this export"); + if ('export_stat_activity' !== $key) { + throw new LogicException("the key {$key} is not used by this export"); } - + switch ($this->action) { case self::SUM: - $header = "Sum of activities duration"; + $header = 'Sum of activities duration'; } - - return function($value) use ($header) { - return $value === '_header' ? + + return function ($value) use ($header) { + return '_header' === $value ? $header : - $value - ; + $value; }; } public function getQueryKeys($data) { - return array('export_stat_activity'); + return ['export_stat_activity']; } public function getResult($qb, $data) @@ -156,4 +95,46 @@ class StatActivityDuration implements ExportInterface return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } + public function getTitle() + { + if (self::SUM === $this->action) { + return 'Sum activity duration'; + } + } + + public function getType() + { + return 'activity'; + } + + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(function ($el) { + return $el['center']; + }, $acl); + $qb = $this->entityManager->createQueryBuilder(); + + if (self::SUM === $this->action) { + $select = 'SUM(activity.durationTime) AS export_stat_activity'; + } + + $qb->select($select) + ->from('ChillActivityBundle:Activity', 'activity') + ->join('activity.person', 'person') + ->join('person.center', 'center') + ->where($qb->expr()->in('center', ':centers')) + ->setParameter(':centers', $centers); + + return $qb; + } + + public function requiredRole() + { + return new Role(ActivityStatsVoter::STATS); + } + + public function supportsModifiers() + { + return ['person', 'activity']; + } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php index dca4cec30..c2a4fbf51 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityDateFilter.php @@ -1,52 +1,36 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; +use Chill\MainBundle\Form\Type\Export\FilterType; +use DateTime; +use Doctrine\ORM\Query\Expr; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormError; -use Chill\MainBundle\Form\Type\Export\FilterType; -use Doctrine\ORM\Query\Expr; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class ActivityDateFilter implements FilterInterface { /** - * * @var TranslatorInterface */ protected $translator; - - function __construct(TranslatorInterface $translator) + + public function __construct(TranslatorInterface $translator) { $this->translator = $translator; } - public function addRole() { return null; @@ -55,15 +39,18 @@ class ActivityDateFilter implements FilterInterface public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->between('activity.date', ':date_from', - ':date_to'); + $clause = $qb->expr()->between( + 'activity.date', + ':date_from', + ':date_to' + ); if ($where instanceof Expr\Andx) { $where->add($clause); } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('date_from', $data['date_from']); $qb->setParameter('date_to', $data['date_to']); @@ -76,55 +63,58 @@ class ActivityDateFilter implements FilterInterface public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Activities after this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + $builder->add('date_from', DateType::class, [ + 'label' => 'Activities after this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Activities before this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + ]); + + $builder->add('date_to', DateType::class, [ + 'label' => 'Activities before this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { /* @var $filterForm \Symfony\Component\Form\FormInterface */ $filterForm = $event->getForm()->getParent(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); - - if ($enabled === true) { + + if (true === $enabled) { // if the filter is enabled, add some validation - $form = $event->getForm(); + $form = $event->getForm(); $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 - if ($date_from === null) { + if (null === $date_from) { $form->get('date_from')->addError(new FormError( $this->translator->trans('This field ' - . 'should not be empty'))); + . 'should not be empty') + )); } - if ($date_to === null) { + + if (null === $date_to) { $form->get('date_to')->addError(new FormError( $this->translator->trans('This field ' - . 'should not be empty'))); - } - + . 'should not be empty') + )); + } + // check that date_from is before date_to if ( - ($date_from !== null && $date_to !== null) - && - $date_from >= $date_to + (null !== $date_from && null !== $date_to) + && $date_from >= $date_to ) { $form->get('date_to')->addError(new FormError( $this->translator->trans('This date should be after ' . 'the date given in "Implied in an activity after ' - . 'this date" field'))); + . 'this date" field') + )); } } }); @@ -132,17 +122,16 @@ class ActivityDateFilter implements FilterInterface public function describeAction($data, $format = 'string') { - return array( - "Filtered by date of activity: only between %date_from% and %date_to%", - array( - "%date_from%" => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y') - )); + return [ + 'Filtered by date of activity: only between %date_from% and %date_to%', + [ + '%date_from%' => $data['date_from']->format('d-m-Y'), + '%date_to%' => $data['date_to']->format('d-m-Y'), + ], ]; } public function getTitle() { - return "Filtered by date activity"; + return 'Filtered by date activity'; } - } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php index 37157af60..f91b17a63 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityReasonFilter.php @@ -1,88 +1,76 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Filter; -use Chill\MainBundle\Export\FilterInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Chill\ActivityBundle\Entity\ActivityReason; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query\Expr; -use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\Query\Expr\Join; -use Symfony\Component\Validator\Context\ExecutionContextInterface; use Chill\MainBundle\Export\ExportElementValidatedInterface; +use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; +use Doctrine\ORM\QueryBuilder; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - * @author Julien Fastré - */ -class ActivityReasonFilter implements FilterInterface, - ExportElementValidatedInterface +class ActivityReasonFilter implements + FilterInterface, + ExportElementValidatedInterface { /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * The repository for activity reasons + * The repository for activity reasons. * * @var EntityRepository */ protected $reasonRepository; - + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + public function __construct( - TranslatableStringHelper $helper, - EntityRepository $reasonRepository + TranslatableStringHelper $helper, + EntityRepository $reasonRepository ) { $this->translatableStringHelper = $helper; - $this->reasonRepository = $reasonRepository; + $this->reasonRepository = $reasonRepository; } - - + + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $join = $qb->getDQLPart('join'); + $join = $qb->getDQLPart('join'); $clause = $qb->expr()->in('reasons', ':selected_activity_reasons'); //dump($join); // add a join to reasons only if needed if ( - (array_key_exists('activity', $join) - && - !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') + ( + array_key_exists('activity', $join) + && !$this->checkJoinAlreadyDefined($join['activity'], 'reasons') ) - OR - (! array_key_exists('activity', $join)) + or (!array_key_exists('activity', $join)) ) { $qb->add( - 'join', - array('activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')), - true - ); + 'join', + ['activity' => new Join(Join::INNER_JOIN, 'activity.reasons', 'reasons')], + true + ); } if ($where instanceof Expr\Andx) { @@ -90,27 +78,10 @@ class ActivityReasonFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('selected_activity_reasons', $data['reasons']); } - - /** - * Check if a join between Activity and Reason is already defined - * - * @param Join[] $joins - * @return boolean - */ - private function checkJoinAlreadyDefined(array $joins, $alias) - { - foreach ($joins as $join) { - if ($join->getAlias() === $alias) { - return true; - } - } - - return false; - } public function applyOn() { @@ -121,49 +92,63 @@ class ActivityReasonFilter implements FilterInterface, { //create a local copy of translatableStringHelper $helper = $this->translatableStringHelper; - - $builder->add('reasons', EntityType::class, array( + + $builder->add('reasons', EntityType::class, [ 'class' => 'ChillActivityBundle:ActivityReason', 'choice_label' => function (ActivityReason $reason) use ($helper) { return $helper->localize($reason->getName()); }, - 'group_by' => function(ActivityReason $reason) use ($helper) { + 'group_by' => function (ActivityReason $reason) use ($helper) { return $helper->localize($reason->getCategory()->getName()); }, 'multiple' => true, - 'expanded' => false - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['reasons'] === null || count($data['reasons']) === 0) { - $context->buildViolation("At least one reason must be choosen") - ->addViolation(); - } + 'expanded' => false, + ]); } - public function getTitle() - { - return 'Filter by reason'; - } - - public function addRole() - { - return new Role(ActivityStatsVoter::STATS); - } - public function describeAction($data, $format = 'string') { // collect all the reasons'name used in this filter in one array $reasonsNames = array_map( - function(ActivityReason $r) { - return "\"".$this->translatableStringHelper->localize($r->getName())."\""; - }, - $this->reasonRepository->findBy(array('id' => $data['reasons']->toArray())) - ); - - return array("Filtered by reasons: only %list%", - ["%list%" => implode(", ", $reasonsNames)]); + function (ActivityReason $r) { + return '"' . $this->translatableStringHelper->localize($r->getName()) . '"'; + }, + $this->reasonRepository->findBy(['id' => $data['reasons']->toArray()]) + ); + + return ['Filtered by reasons: only %list%', + ['%list%' => implode(', ', $reasonsNames)], ]; + } + + public function getTitle() + { + return 'Filter by reason'; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['reasons'] || count($data['reasons']) === 0) { + $context->buildViolation('At least one reason must be choosen') + ->addViolation(); + } + } + + /** + * Check if a join between Activity and Reason is already defined. + * + * @param Join[] $joins + * @param mixed $alias + * + * @return bool + */ + private function checkJoinAlreadyDefined(array $joins, $alias) + { + foreach ($joins as $join) { + if ($join->getAlias() === $alias) { + return true; + } + } + + return false; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php index b3616da10..a9c11a9a7 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/ActivityTypeFilter.php @@ -1,67 +1,57 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Filter; -use Chill\MainBundle\Export\FilterInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query\Expr; -use Symfony\Component\Security\Core\Role\Role; -use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; -use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\Query\Expr\Join; -use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\ActivityBundle\Entity\ActivityType; +use Chill\ActivityBundle\Security\Authorization\ActivityStatsVoter; +use Chill\MainBundle\Export\ExportElementValidatedInterface; +use Chill\MainBundle\Export\FilterInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\Query\Expr\Join; +use Doctrine\ORM\QueryBuilder; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - */ -class ActivityTypeFilter implements FilterInterface, - ExportElementValidatedInterface +class ActivityTypeFilter implements + FilterInterface, + ExportElementValidatedInterface { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + /** - * The repository for activity reasons + * The repository for activity reasons. * * @var EntityRepository */ protected $typeRepository; - + public function __construct( - TranslatableStringHelper $helper, - EntityRepository $typeRepository + TranslatableStringHelper $helper, + EntityRepository $typeRepository ) { $this->translatableStringHelper = $helper; $this->typeRepository = $typeRepository; } - - + + public function addRole() + { + return new Role(ActivityStatsVoter::STATS); + } + public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); @@ -72,27 +62,10 @@ class ActivityTypeFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('selected_activity_types', $data['types']); } - - /** - * Check if a join between Activity and Reason is already defined - * - * @param Join[] $joins - * @return boolean - */ - private function checkJoinAlreadyDefined(array $joins, $alias) - { - foreach ($joins as $join) { - if ($join->getAlias() === $alias) { - return true; - } - } - - return false; - } public function applyOn() { @@ -103,46 +76,60 @@ class ActivityTypeFilter implements FilterInterface, { //create a local copy of translatableStringHelper $helper = $this->translatableStringHelper; - - $builder->add('types', EntityType::class, array( + + $builder->add('types', EntityType::class, [ 'class' => ActivityType::class, 'choice_label' => function (ActivityType $type) use ($helper) { return $helper->localize($type->getName()); }, 'multiple' => true, - 'expanded' => false - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['types'] === null || count($data['types']) === 0) { - $context->buildViolation("At least one type must be choosen") - ->addViolation(); - } + 'expanded' => false, + ]); } - public function getTitle() - { - return 'Filter by activity type'; - } - - public function addRole() - { - return new Role(ActivityStatsVoter::STATS); - } - public function describeAction($data, $format = 'string') { // collect all the reasons'name used in this filter in one array $reasonsNames = array_map( - function(ActivityType $t) { - return "\"".$this->translatableStringHelper->localize($t->getName())."\""; - }, - $this->typeRepository->findBy(array('id' => $data['types']->toArray())) - ); - - return array("Filtered by activity type: only %list%", - ["%list%" => implode(", ", $reasonsNames)]); + function (ActivityType $t) { + return '"' . $this->translatableStringHelper->localize($t->getName()) . '"'; + }, + $this->typeRepository->findBy(['id' => $data['types']->toArray()]) + ); + + return ['Filtered by activity type: only %list%', + ['%list%' => implode(', ', $reasonsNames)], ]; + } + + public function getTitle() + { + return 'Filter by activity type'; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['types'] || count($data['types']) === 0) { + $context->buildViolation('At least one type must be choosen') + ->addViolation(); + } + } + + /** + * Check if a join between Activity and Reason is already defined. + * + * @param Join[] $joins + * @param mixed $alias + * + * @return bool + */ + private function checkJoinAlreadyDefined(array $joins, $alias) + { + foreach ($joins as $join) { + if ($join->getAlias() === $alias) { + return true; + } + } + + return false; } } diff --git a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php index cf444bd0a..f6f1ed980 100644 --- a/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php +++ b/src/Bundle/ChillActivityBundle/Export/Filter/PersonHavingActivityBetweenDateFilter.php @@ -1,79 +1,60 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Export\Filter; +use Chill\ActivityBundle\Entity\ActivityReason; +use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; +use Chill\MainBundle\Form\Type\Export\FilterType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Export\Declarations; +use DateTime; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Query\Expr; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormError; -use Chill\MainBundle\Form\Type\Export\FilterType; -use Doctrine\ORM\Query\Expr; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\ActivityBundle\Entity\ActivityReason; -use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\EntityManager; -use Chill\PersonBundle\Export\Declarations; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Chill\MainBundle\Export\ExportElementValidatedInterface; -/** - * - * - * @author Julien Fastré - */ -class PersonHavingActivityBetweenDateFilter implements FilterInterface, +class PersonHavingActivityBetweenDateFilter implements + FilterInterface, ExportElementValidatedInterface { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * * @var EntityRepository */ protected $activityReasonRepository; - + /** - * - * @var TranslatorInterface + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * @var TranslatorInterface */ protected $translator; - + public function __construct( - TranslatableStringHelper $translatableStringHelper, - EntityRepository $activityReasonRepository, - TranslatorInterface $translator + TranslatableStringHelper $translatableStringHelper, + EntityRepository $activityReasonRepository, + TranslatorInterface $translator ) { $this->translatableStringHelper = $translatableStringHelper; $this->activityReasonRepository = $activityReasonRepository; - $this->translator = $translator; + $this->translator = $translator; } - public function addRole() { return null; @@ -83,24 +64,26 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, { // create a query for activity $sqb = $qb->getEntityManager()->createQueryBuilder(); - $sqb->select("person_person_having_activity.id") - ->from("ChillActivityBundle:Activity", "activity_person_having_activity") - ->join("activity_person_having_activity.person", "person_person_having_activity") - ; + $sqb->select('person_person_having_activity.id') + ->from('ChillActivityBundle:Activity', 'activity_person_having_activity') + ->join('activity_person_having_activity.person', 'person_person_having_activity'); // add clause between date - $sqb->where("activity_person_having_activity.date BETWEEN " - . ":person_having_activity_between_date_from" - . " AND " - . ":person_having_activity_between_date_to"); + $sqb->where('activity_person_having_activity.date BETWEEN ' + . ':person_having_activity_between_date_from' + . ' AND ' + . ':person_having_activity_between_date_to'); // add clause activity reason - $sqb->join('activity_person_having_activity.reasons', - 'reasons_person_having_activity'); + $sqb->join( + 'activity_person_having_activity.reasons', + 'reasons_person_having_activity' + ); $sqb->andWhere( - $sqb->expr()->in( - 'reasons_person_having_activity', - ":person_having_activity_reasons") - ); - + $sqb->expr()->in( + 'reasons_person_having_activity', + ':person_having_activity_reasons' + ) + ); + $where = $qb->getDQLPart('where'); $clause = $qb->expr()->in('person.id', $sqb->getDQL()); @@ -109,12 +92,16 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); - $qb->setParameter('person_having_activity_between_date_from', - $data['date_from']); - $qb->setParameter('person_having_activity_between_date_to', - $data['date_to']); + $qb->setParameter( + 'person_having_activity_between_date_from', + $data['date_from'] + ); + $qb->setParameter( + 'person_having_activity_between_date_to', + $data['date_to'] + ); $qb->setParameter('person_having_activity_reasons', $data['reasons']); } @@ -125,104 +112,107 @@ class PersonHavingActivityBetweenDateFilter implements FilterInterface, public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Implied in an activity after this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + $builder->add('date_from', DateType::class, [ + 'label' => 'Implied in an activity after this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Implied in an activity before this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + ]); + + $builder->add('date_to', DateType::class, [ + 'label' => 'Implied in an activity before this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('reasons', EntityType::class, array( + ]); + + $builder->add('reasons', EntityType::class, [ 'class' => 'ChillActivityBundle:ActivityReason', 'choice_label' => function (ActivityReason $reason) { return $this->translatableStringHelper - ->localize($reason->getName()); + ->localize($reason->getName()); }, - 'group_by' => function(ActivityReason $reason) { + 'group_by' => function (ActivityReason $reason) { return $this->translatableStringHelper - ->localize($reason->getCategory()->getName()); + ->localize($reason->getCategory()->getName()); }, 'data' => $this->activityReasonRepository->findAll(), 'multiple' => true, 'expanded' => false, - 'label' => "Activity reasons for those activities" - )); - - $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { + 'label' => 'Activity reasons for those activities', + ]); + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { /* @var $filterForm \Symfony\Component\Form\FormInterface */ $filterForm = $event->getForm()->getParent(); $enabled = $filterForm->get(FilterType::ENABLED_FIELD)->getData(); - - if ($enabled === true) { + + if (true === $enabled) { // if the filter is enabled, add some validation - $form = $event->getForm(); + $form = $event->getForm(); $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 - if ($date_from === null) { + if (null === $date_from) { $form->get('date_from')->addError(new FormError( $this->translator->trans('This field ' - . 'should not be empty'))); + . 'should not be empty') + )); } - if ($date_to === null) { + + if (null === $date_to) { $form->get('date_to')->addError(new FormError( $this->translator->trans('This field ' - . 'should not be empty'))); - } - + . 'should not be empty') + )); + } + // check that date_from is before date_to if ( - ($date_from !== null && $date_to !== null) - && - $date_from >= $date_to + (null !== $date_from && null !== $date_to) + && $date_from >= $date_to ) { $form->get('date_to')->addError(new FormError( $this->translator->trans('This date ' . 'should be after the date given in "Implied in an ' - . 'activity after this date" field'))); + . 'activity after this date" field') + )); } } }); } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['reasons'] === null || count($data['reasons']) === 0) { - $context->buildViolation("At least one reason must be choosen") - ->addViolation(); - } - } public function describeAction($data, $format = 'string') { - return array( - "Filtered by person having an activity between %date_from% and " - . "%date_to% with reasons %reasons_name%", - array( - "%date_from%" => $data['date_from']->format('d-m-Y'), - '%date_to%' => $data['date_to']->format('d-m-Y'), - "%reasons_name%" => implode(", ", array_map( - function (ActivityReason $r) { - return '"'.$this->translatableStringHelper-> - localize($r->getName()).'"'; - }, - $data['reasons'])) - )); + return [ + 'Filtered by person having an activity between %date_from% and ' + . '%date_to% with reasons %reasons_name%', + [ + '%date_from%' => $data['date_from']->format('d-m-Y'), + '%date_to%' => $data['date_to']->format('d-m-Y'), + '%reasons_name%' => implode(', ', array_map( + function (ActivityReason $r) { + return '"' . $this->translatableStringHelper-> + localize($r->getName()) . '"'; + }, + $data['reasons'] + )), + ], ]; } public function getTitle() { - return "Filtered by person having an activity in a period"; + return 'Filtered by person having an activity in a period'; } + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['reasons'] || count($data['reasons']) === 0) { + $context->buildViolation('At least one reason must be choosen') + ->addViolation(); + } + } } diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityReasonCategoryType.php b/src/Bundle/ChillActivityBundle/Form/ActivityReasonCategoryType.php index 5f566393f..2f3589d7a 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityReasonCategoryType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityReasonCategoryType.php @@ -1,25 +1,27 @@ add('name', TranslatableStringFormType::class) - ->add('active', CheckboxType::class, array('required' => false)) - ; + ->add('active', CheckboxType::class, ['required' => false]); } /** @@ -27,9 +29,9 @@ class ActivityReasonCategoryType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReasonCategory', + ]); } /** diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityReasonType.php b/src/Bundle/ChillActivityBundle/Form/ActivityReasonType.php index f46930faa..38c65bb2a 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityReasonType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityReasonType.php @@ -1,37 +1,36 @@ add('name', TranslatableStringFormType::class) - ->add('active', CheckboxType::class, array('required' => false)) - ->add('category', TranslatableActivityReasonCategory::class) - ; + ->add('active', CheckboxType::class, ['required' => false]) + ->add('category', TranslatableActivityReasonCategory::class); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\ActivityBundle\Entity\ActivityReason', + ]); } /** diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 3a9a307fd..f276eb92c 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -1,65 +1,72 @@ getToken()->getUser() instanceof User) { - throw new \RuntimeException("you should have a valid user"); + throw new RuntimeException('you should have a valid user'); } $this->user = $tokenStorage->getToken()->getUser(); $this->authorizationHelper = $authorizationHelper; @@ -68,103 +75,98 @@ class ActivityType extends AbstractType $this->timeChoices = $timeChoices; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { // handle times choices - $timeChoices = array(); + $timeChoices = []; foreach ($this->timeChoices as $e) { $timeChoices[$e['label']] = $e['seconds']; - }; + } $durationTimeTransformer = new DateTimeToTimestampTransformer('GMT', 'GMT'); - $durationTimeOptions = array( - 'choices' => $timeChoices, - 'placeholder' => 'Choose the duration', - ); + $durationTimeOptions = [ + 'choices' => $timeChoices, + 'placeholder' => 'Choose the duration', + ]; $builder - ->add('date', ChillDateType::class, array( - 'required' => true - )) + ->add('date', ChillDateType::class, [ + 'required' => true, + ]) ->add('durationTime', ChoiceType::class, $durationTimeOptions) - ->add('attendee', ChoiceType::class, array( - 'expanded' => true, - 'required' => false, - 'choices' => array( - 'present' => true, - 'not present' => false - ) - )) + ->add('attendee', ChoiceType::class, [ + 'expanded' => true, + 'required' => false, + 'choices' => [ + 'present' => true, + 'not present' => false, + ], + ]) ->add('user', UserPickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'] + 'role' => $options['role'], ]) ->add('scope', ScopePickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'] + 'role' => $options['role'], ]) - ->add('reasons', TranslatableActivityReason::class, array( + ->add('reasons', TranslatableActivityReason::class, [ 'multiple' => true, 'required' => false, - )) - ->add('type', TranslatableActivityType::class, array( + ]) + ->add('type', TranslatableActivityType::class, [ 'placeholder' => 'Choose a type', - 'active_only' => true - )) + 'active_only' => true, + ]) ->add('comment', CommentType::class, [ 'required' => false, - ]) - ; + ]); $builder->get('durationTime') - ->addModelTransformer($durationTimeTransformer); - + ->addModelTransformer($durationTimeTransformer); $builder->get('durationTime') - ->addEventListener( - FormEvents::PRE_SET_DATA, - function(FormEvent $formEvent) use ( - $timeChoices, - $builder, - $durationTimeTransformer, - $durationTimeOptions - ) - { - // set the timezone to GMT, and fix the difference between current and GMT - // the datetimetransformer will then handle timezone as GMT - $timezoneUTC = new \DateTimeZone('GMT'); - /* @var $data \DateTime */ - $data = $formEvent->getData() === NULL ? - \DateTime::createFromFormat('U', 300) : + ->addEventListener( + FormEvents::PRE_SET_DATA, + function (FormEvent $formEvent) use ( + $timeChoices, + $builder, + $durationTimeTransformer, + $durationTimeOptions + ) { + // set the timezone to GMT, and fix the difference between current and GMT + // the datetimetransformer will then handle timezone as GMT + $timezoneUTC = new DateTimeZone('GMT'); + /* @var $data \DateTime */ + $data = $formEvent->getData() === null ? + DateTime::createFromFormat('U', 300) : $formEvent->getData(); - $seconds = $data->getTimezone()->getOffset($data); - $data->setTimeZone($timezoneUTC); - $data->add(new \DateInterval('PT'.$seconds.'S')); + $seconds = $data->getTimezone()->getOffset($data); + $data->setTimeZone($timezoneUTC); + $data->add(new DateInterval('PT' . $seconds . 'S')); - // test if the timestamp is in the choices. - // If not, recreate the field with the new timestamp - if (!in_array($data->getTimestamp(), $timeChoices)) { - // the data are not in the possible values. add them - $timeChoices[$data->format('H:i')] = $data->getTimestamp(); - $form = $builder->create( - 'durationTime', - ChoiceType::class, - array_merge( - $durationTimeOptions, - array( - 'choices' => $timeChoices, - 'auto_initialize' => false - ) - )); - $form->addModelTransformer($durationTimeTransformer); - $formEvent->getForm()->getParent()->add($form->getForm()); - } - }); + // test if the timestamp is in the choices. + // If not, recreate the field with the new timestamp + if (!in_array($data->getTimestamp(), $timeChoices)) { + // the data are not in the possible values. add them + $timeChoices[$data->format('H:i')] = $data->getTimestamp(); + $form = $builder->create( + 'durationTime', + ChoiceType::class, + array_merge( + $durationTimeOptions, + [ + 'choices' => $timeChoices, + 'auto_initialize' => false, + ] + ) + ); + $form->addModelTransformer($durationTimeTransformer); + $formEvent->getForm()->getParent()->add($form->getForm()); + } + } + ); } /** @@ -172,15 +174,14 @@ class ActivityType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\Activity' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\ActivityBundle\Entity\Activity', + ]); $resolver - ->setRequired(array('center', 'role')) - ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center') - ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') - ; + ->setRequired(['center', 'role']) + ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center') + ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role'); } /** diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php index a402f584c..25ab338d0 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php @@ -1,30 +1,33 @@ add('name', TranslatableStringFormType::class) - ->add('active', ChoiceType::class, array( - 'choices' => array( + ->add('active', ChoiceType::class, [ + 'choices' => [ 'Yes' => true, - 'No' => false - ), - 'expanded' => true - )); + 'No' => false, + ], + 'expanded' => true, + ]); } /** @@ -32,9 +35,9 @@ class ActivityTypeType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ActivityBundle\Entity\ActivityType' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\ActivityBundle\Entity\ActivityType', + ]); } /** diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReason.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReason.php index 4bf4aa9da..867c74b10 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReason.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReason.php @@ -1,54 +1,37 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\EntityRepository; use Chill\ActivityBundle\Entity\ActivityReason; use Chill\ActivityBundle\Templating\Entity\ActivityReasonRender; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * FormType to choose amongst activity reasons - * + * FormType to choose amongst activity reasons. */ class TranslatableActivityReason extends AbstractType { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * * @var ActivityReasonRender */ protected $reasonRender; + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + public function __construct( TranslatableStringHelper $translatableStringHelper, ActivityReasonRender $reasonRender @@ -57,6 +40,30 @@ class TranslatableActivityReason extends AbstractType $this->reasonRender = $reasonRender; } + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'class' => 'ChillActivityBundle:ActivityReason', + 'choice_label' => function (ActivityReason $choice) { + return $this->reasonRender->renderString($choice, []); + }, + 'group_by' => function (ActivityReason $choice): ?string { + if (null !== $category = $choice->getCategory()) { + return $this->translatableStringHelper->localize($category->getName()); + } + + return null; + }, + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('r') + ->where('r.active = true'); + }, + 'attr' => ['class' => ' select2 '], + ] + ); + } + public function getBlockPrefix() { return 'translatable_activity_reason'; @@ -66,28 +73,4 @@ class TranslatableActivityReason extends AbstractType { return EntityType::class; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - array( - 'class' => 'ChillActivityBundle:ActivityReason', - 'choice_label' => function(ActivityReason $choice) { - return $this->reasonRender->renderString($choice, []); - }, - 'group_by' => function(ActivityReason $choice): ?string { - if (null !== $category = $choice->getCategory()) { - return $this->translatableStringHelper->localize($category->getName()); - } - - return null; - }, - 'query_builder' => function (EntityRepository $er) { - return $er->createQueryBuilder('r') - ->where('r.active = true'); - }, - 'attr' => [ 'class' => ' select2 '] - ) - ); - } } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReasonCategory.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReasonCategory.php index 6dd04023c..b0b064927 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReasonCategory.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityReasonCategory.php @@ -1,40 +1,23 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Description of TranslatableActivityReasonCategory - * - * @author Champs-Libres Coop + * Description of TranslatableActivityReasonCategory. */ - - class TranslatableActivityReasonCategory extends AbstractType { /** @@ -47,6 +30,21 @@ class TranslatableActivityReasonCategory extends AbstractType $this->requestStack = $requestStack; } + public function configureOptions(OptionsResolver $resolver) + { + $locale = $this->requestStack->getCurrentRequest()->getLocale(); + $resolver->setDefaults( + [ + 'class' => 'ChillActivityBundle:ActivityReasonCategory', + 'choice_label' => 'name[' . $locale . ']', + 'query_builder' => function (EntityRepository $er) { + return $er->createQueryBuilder('c') + ->where('c.active = true'); + }, + ] + ); + } + public function getBlockPrefix() { return 'translatable_activity_reason_category'; @@ -56,19 +54,4 @@ class TranslatableActivityReasonCategory extends AbstractType { return EntityType::class; } - - public function configureOptions(OptionsResolver $resolver) - { - $locale = $this->requestStack->getCurrentRequest()->getLocale(); - $resolver->setDefaults( - array( - 'class' => 'ChillActivityBundle:ActivityReasonCategory', - 'choice_label' => 'name['.$locale.']', - 'query_builder' => function (EntityRepository $er) { - return $er->createQueryBuilder('c') - ->where('c.active = true'); - } - ) - ); - } } diff --git a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php index f21184a30..8700cf38a 100644 --- a/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/Type/TranslatableActivityType.php @@ -1,60 +1,67 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Chill\ActivityBundle\Entity\ActivityType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\EntityRepository; -use Chill\ActivityBundle\Entity\ActivityType; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Description of TranslatableActivityType - * - * @author Champs-Libres Coop + * Description of TranslatableActivityType. */ class TranslatableActivityType extends AbstractType { + protected $activityTypeRepository; /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - protected $activityTypeRepository; - public function __construct( - TranslatableStringHelper $helper, - EntityRepository $activityTypeRepository - ) - { + TranslatableStringHelper $helper, + EntityRepository $activityTypeRepository + ) { $this->translatableStringHelper = $helper; $this->activityTypeRepository = $activityTypeRepository; } + public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) + { + /* @var $qb \Doctrine\ORM\QueryBuilder */ + $qb = $options['query_builder']; + + if (true === $options['active_only']) { + $qb->where($qb->expr()->eq('at.active', ':active')); + $qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN); + } + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'class' => 'ChillActivityBundle:ActivityType', + 'active_only' => true, + 'query_builder' => $this->activityTypeRepository + ->createQueryBuilder('at'), + 'choice_label' => function (ActivityType $type) { + return $this->translatableStringHelper->localize($type->getName()); + }, + ] + ); + } + public function getBlockPrefix() { return 'translatable_activity_type'; @@ -64,30 +71,4 @@ class TranslatableActivityType extends AbstractType { return EntityType::class; } - - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder, array $options) { - /* @var $qb \Doctrine\ORM\QueryBuilder */ - $qb = $options['query_builder']; - - if ($options['active_only'] === true) { - $qb->where($qb->expr()->eq('at.active', ':active')); - $qb->setParameter('active', true, \Doctrine\DBAL\Types\Type::BOOLEAN); - } - } - - public function configureOptions(OptionsResolver $resolver) - { - - $resolver->setDefaults( - array( - 'class' => 'ChillActivityBundle:ActivityType', - 'active_only' => true, - 'query_builder' => $this->activityTypeRepository - ->createQueryBuilder('at'), - 'choice_label' => function (ActivityType $type) { - return $this->translatableStringHelper->localize($type->getName()); - } - ) - ); - } } diff --git a/src/Bundle/ChillActivityBundle/Menu/MenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/MenuBuilder.php index f11aa28bc..b2ca87c19 100644 --- a/src/Bundle/ChillActivityBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/MenuBuilder.php @@ -1,45 +1,42 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\ActivityBundle\Menu; + +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Knp\Menu\MenuItem; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Translation\TranslatorInterface; + class MenuBuilder implements LocalMenuBuilderInterface { /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + + /** + * @var TranslatorInterface + */ + protected $translator; + public function __construct( - TokenStorageInterface $tokenStorage, - TranslatorInterface $translator, + TokenStorageInterface $tokenStorage, + TranslatorInterface $translator, AuthorizationHelper $authorizationHelper ) { $this->tokenStorage = $tokenStorage; @@ -47,42 +44,41 @@ class MenuBuilder implements LocalMenuBuilderInterface $this->authorizationHelper = $authorizationHelper; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ - $person = $parameters['person']; - $user = $this->tokenStorage->getToken()->getUser(); + $person = $parameters['person']; + $user = $this->tokenStorage->getToken()->getUser(); $roleSee = new Role(ActivityVoter::SEE); $roleAdd = new Role(ActivityVoter::CREATE); - + if ($this->authorizationHelper->userHasAccess($user, $person, $roleSee)) { $menu->addChild($this->translator->trans('Activity list'), [ - 'route' => 'chill_activity_activity_list', - 'routeParameters' => [ - 'person_id' => $person->getId() - ] - ]) + 'route' => 'chill_activity_activity_list', + 'routeParameters' => [ + 'person_id' => $person->getId(), + ], + ]) ->setExtras([ - 'order' => 201 + 'order' => 201, ]); } - + if ($this->authorizationHelper->userHasAccess($user, $person, $roleAdd)) { $menu->addChild($this->translator->trans('Add a new activity'), [ - 'route' => 'chill_activity_activity_new', - 'routeParameters' => [ - 'person_id' => $person->getId() - ] - ]) + 'route' => 'chill_activity_activity_new', + 'routeParameters' => [ + 'person_id' => $person->getId(), + ], + ]) ->setExtras([ - 'order' => 200 + 'order' => 200, ]); } } public static function getMenuIds(): array { - return [ 'person' ]; + return ['person']; } } diff --git a/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php index 7c8092227..20590b8c9 100644 --- a/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillActivityBundle/Menu/PersonMenuBuilder.php @@ -1,78 +1,65 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\ActivityBundle\Menu; +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class PersonMenuBuilder implements LocalMenuBuilderInterface { /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + + /** + * @var TranslatorInterface + */ + protected $translator; + public function __construct( AuthorizationCheckerInterface $authorizationChecker, - TranslatorInterface $translator) - { + TranslatorInterface $translator + ) { $this->translator = $translator; $this->authorizationChecker = $authorizationChecker; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person']; - + if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) { $menu->addChild( - $this->translator->trans('Activity list'), [ + $this->translator->trans('Activity list'), + [ 'route' => 'chill_activity_activity_list', - 'routeParameters' => [ 'person_id' => $person->getId() ], - ]) - ->setExtra('order', 201) - ; + 'routeParameters' => ['person_id' => $person->getId()], + ] + ) + ->setExtra('order', 201); } + if ($this->authorizationChecker->isGranted(ActivityVoter::CREATE, $person)) { $menu->addChild( - $this->translator->trans('Add a new activity'), [ + $this->translator->trans('Add a new activity'), + [ 'route' => 'chill_activity_activity_new', - 'routeParameters' => [ 'person_id' => $person->getId() ], - ]) - ->setExtra('order', 200) - ; + 'routeParameters' => ['person_id' => $person->getId()], + ] + ) + ->setExtra('order', 200); } } diff --git a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php index d639d79d5..ac7b207d0 100644 --- a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php +++ b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/AppKernel.php @@ -1,13 +1,36 @@ load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); - } - - /** - * @return string - */ - public function getCacheDir() - { - return sys_get_temp_dir().'/ActivityBundle/cache'; - } - - /** - * @return string - */ - public function getLogDir() - { - return sys_get_temp_dir().'/ActivityBundle/logs'; + $loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml'); } } diff --git a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/autoload.php b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/autoload.php index 39dc0e2ba..a2dfe7f92 100644 --- a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/autoload.php +++ b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/app/autoload.php @@ -1,11 +1,18 @@ services = $this->scopedServices = - $this->scopeStacks = array(); - $this->scopes = array('request' => 'container'); - $this->scopeChildren = array('request' => array()); - $this->methodMap = array( + $this->scopeStacks = []; + $this->scopes = ['request' => 'container']; + $this->scopeChildren = ['request' => []]; + $this->methodMap = [ 'annotation_reader' => 'getAnnotationReaderService', 'assetic.asset_factory' => 'getAssetic_AssetFactoryService', 'assetic.asset_manager' => 'getAssetic_AssetManagerService', @@ -279,8 +287,8 @@ class appDevDebugProjectContainer extends Container 'web_profiler.controller.exception' => 'getWebProfiler_Controller_ExceptionService', 'web_profiler.controller.profiler' => 'getWebProfiler_Controller_ProfilerService', 'web_profiler.controller.router' => 'getWebProfiler_Controller_RouterService', - ); - $this->aliases = array( + ]; + $this->aliases = [ 'console.command.sensiolabs_security_command_securitycheckercommand' => 'sensio_distribution.security_checker.command', 'database_connection' => 'doctrine.dbal.default_connection', 'doctrine.orm.default_metadata_cache' => 'doctrine_cache.providers.doctrine.orm.default_metadata_cache', @@ -294,17 +302,46 @@ class appDevDebugProjectContainer extends Container 'swiftmailer.mailer' => 'swiftmailer.mailer.default', 'swiftmailer.plugin.messagelogger' => 'swiftmailer.mailer.default.plugin.messagelogger', 'swiftmailer.transport' => 'swiftmailer.mailer.default.transport', - ); + ]; } - /** - * {@inheritdoc} - */ public function compile() { throw new LogicException('You cannot compile a dumped frozen container.'); } + public function getParameter($name) + { + $name = strtolower($name); + + if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + + return $this->parameters[$name]; + } + + public function getParameterBag() + { + if (null === $this->parameterBag) { + $this->parameterBag = new FrozenParameterBag($this->parameters); + } + + return $this->parameterBag; + } + + public function hasParameter($name) + { + $name = strtolower($name); + + return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters); + } + + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + /** * Gets the 'annotation_reader' service. * @@ -318,6 +355,23 @@ class appDevDebugProjectContainer extends Container return $this->services['annotation_reader'] = new \Doctrine\Common\Annotations\FileCacheReader(new \Doctrine\Common\Annotations\AnnotationReader(), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/annotations', true); } + /** + * Gets the 'assetic.asset_factory' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Bundle\AsseticBundle\Factory\AssetFactory A Symfony\Bundle\AsseticBundle\Factory\AssetFactory instance. + */ + protected function getAssetic_AssetFactoryService() + { + return $this->services['assetic.asset_factory'] = new \Symfony\Bundle\AsseticBundle\Factory\AssetFactory($this->get('kernel'), $this, $this->getParameterBag(), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', true); + } + /** * Gets the 'assetic.asset_manager' service. * @@ -330,10 +384,10 @@ class appDevDebugProjectContainer extends Container { $a = $this->get('templating.loader'); - $this->services['assetic.asset_manager'] = $instance = new \Assetic\Factory\LazyAssetManager($this->get('assetic.asset_factory'), array('twig' => new \Assetic\Factory\Loader\CachedFormulaLoader(new \Assetic\Extension\Twig\TwigFormulaLoader($this->get('twig'), $this->get('monolog.logger.assetic', ContainerInterface::NULL_ON_INVALID_REFERENCE)), new \Assetic\Cache\ConfigCache('/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/assetic/config'), true))); + $this->services['assetic.asset_manager'] = $instance = new \Assetic\Factory\LazyAssetManager($this->get('assetic.asset_factory'), ['twig' => new \Assetic\Factory\Loader\CachedFormulaLoader(new \Assetic\Extension\Twig\TwigFormulaLoader($this->get('twig'), $this->get('monolog.logger.assetic', ContainerInterface::NULL_ON_INVALID_REFERENCE)), new \Assetic\Cache\ConfigCache('/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/assetic/config'), true)]); - $instance->addResource(new \Symfony\Bundle\AsseticBundle\Factory\Resource\CoalescingDirectoryResource(array(0 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillPersonBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources/ChillPersonBundle/views', '/\\.[^.]+\\.twig$/'), 1 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillPersonBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/views', '/\\.[^.]+\\.twig$/'))), 'twig'); - $instance->addResource(new \Symfony\Bundle\AsseticBundle\Factory\Resource\CoalescingDirectoryResource(array(0 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillMainBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources/ChillMainBundle/views', '/\\.[^.]+\\.twig$/'), 1 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillMainBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/views', '/\\.[^.]+\\.twig$/'))), 'twig'); + $instance->addResource(new \Symfony\Bundle\AsseticBundle\Factory\Resource\CoalescingDirectoryResource([0 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillPersonBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources/ChillPersonBundle/views', '/\\.[^.]+\\.twig$/'), 1 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillPersonBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/views', '/\\.[^.]+\\.twig$/')]), 'twig'); + $instance->addResource(new \Symfony\Bundle\AsseticBundle\Factory\Resource\CoalescingDirectoryResource([0 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillMainBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources/ChillMainBundle/views', '/\\.[^.]+\\.twig$/'), 1 => new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, 'ChillMainBundle', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/views', '/\\.[^.]+\\.twig$/')]), 'twig'); $instance->addResource(new \Symfony\Bundle\AsseticBundle\Factory\Resource\DirectoryResource($a, '', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources/views', '/\\.[^.]+\\.twig$/'), 'twig'); return $instance; @@ -362,7 +416,7 @@ class appDevDebugProjectContainer extends Container */ protected function getAssetic_FilterManagerService() { - return $this->services['assetic.filter_manager'] = new \Symfony\Bundle\AsseticBundle\FilterManager($this, array('cssrewrite' => 'assetic.filter.cssrewrite')); + return $this->services['assetic.filter_manager'] = new \Symfony\Bundle\AsseticBundle\FilterManager($this, ['cssrewrite' => 'assetic.filter.cssrewrite']); } /** @@ -388,7 +442,7 @@ class appDevDebugProjectContainer extends Container */ protected function getAssets_PackagesService() { - return $this->services['assets.packages'] = new \Symfony\Component\Asset\Packages(new \Symfony\Component\Asset\PathPackage('', new \Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy(), $this->get('assets.context')), array()); + return $this->services['assets.packages'] = new \Symfony\Component\Asset\Packages(new \Symfony\Component\Asset\PathPackage('', new \Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy(), $this->get('assets.context')), []); } /** @@ -401,7 +455,7 @@ class appDevDebugProjectContainer extends Container */ protected function getCacheClearerService() { - return $this->services['cache_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer(array()); + return $this->services['cache_clearer'] = new \Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer([]); } /** @@ -414,7 +468,7 @@ class appDevDebugProjectContainer extends Container */ protected function getCacheWarmerService() { - return $this->services['cache_warmer'] = new \Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate(array(0 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplatePathsCacheWarmer(new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinder($this->get('kernel'), $this->get('templating.filename_parser'), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources'), $this->get('templating.locator')), 1 => new \Symfony\Bundle\AsseticBundle\CacheWarmer\AssetManagerCacheWarmer($this), 2 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TranslationsCacheWarmer($this->get('translator.default')), 3 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer($this->get('router')), 4 => new \Symfony\Bridge\Doctrine\CacheWarmer\ProxyCacheWarmer($this->get('doctrine')))); + return $this->services['cache_warmer'] = new \Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate([0 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplatePathsCacheWarmer(new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TemplateFinder($this->get('kernel'), $this->get('templating.filename_parser'), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/Resources'), $this->get('templating.locator')), 1 => new \Symfony\Bundle\AsseticBundle\CacheWarmer\AssetManagerCacheWarmer($this), 2 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\TranslationsCacheWarmer($this->get('translator.default')), 3 => new \Symfony\Bundle\FrameworkBundle\CacheWarmer\RouterCacheWarmer($this->get('router')), 4 => new \Symfony\Bridge\Doctrine\CacheWarmer\ProxyCacheWarmer($this->get('doctrine'))]); } /** @@ -443,19 +497,6 @@ class appDevDebugProjectContainer extends Container return $this->services['chill.custom_field.custom_field_choice_type'] = new \Chill\CustomFieldsBundle\Form\CustomFieldType($this->get('chill.custom_field.provider')); } - /** - * Gets the 'chill.custom_field.custom_field_type' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Chill\CustomFieldsBundle\Form\Type\CustomFieldType A Chill\CustomFieldsBundle\Form\Type\CustomFieldType instance. - */ - protected function getChill_CustomField_CustomFieldTypeService() - { - return $this->services['chill.custom_field.custom_field_type'] = new \Chill\CustomFieldsBundle\Form\Type\CustomFieldType($this->get('doctrine.orm.default_entity_manager'), $this->get('chill.custom_field.provider')); - } - /** * Gets the 'chill.custom_field.custom_fields_group_linked_custom_fields' service. * @@ -479,7 +520,7 @@ class appDevDebugProjectContainer extends Container */ protected function getChill_CustomField_CustomFieldsGroupTypeService() { - return $this->services['chill.custom_field.custom_fields_group_type'] = new \Chill\CustomFieldsBundle\Form\CustomFieldsGroupType(array(0 => array('class' => 'Chill\\PersonBundle\\Entity\\Person', 'name' => 'PersonEntity', 'options' => array())), $this->get('translator')); + return $this->services['chill.custom_field.custom_fields_group_type'] = new \Chill\CustomFieldsBundle\Form\CustomFieldsGroupType([0 => ['class' => 'Chill\\PersonBundle\\Entity\\Person', 'name' => 'PersonEntity', 'options' => []]], $this->get('translator')); } /** @@ -495,6 +536,19 @@ class appDevDebugProjectContainer extends Container return $this->services['chill.custom_field.custom_fields_title_type'] = new \Chill\CustomFieldsBundle\Form\Type\CustomFieldsTitleType(); } + /** + * Gets the 'chill.custom_field.custom_field_type' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Chill\CustomFieldsBundle\Form\Type\CustomFieldType A Chill\CustomFieldsBundle\Form\Type\CustomFieldType instance. + */ + protected function getChill_CustomField_CustomFieldTypeService() + { + return $this->services['chill.custom_field.custom_field_type'] = new \Chill\CustomFieldsBundle\Form\Type\CustomFieldType($this->get('doctrine.orm.default_entity_manager'), $this->get('chill.custom_field.provider')); + } + /** * Gets the 'chill.custom_field.helper' service. * @@ -658,7 +712,7 @@ class appDevDebugProjectContainer extends Container */ protected function getChill_Main_Form_Type_Translatable_StringService() { - return $this->services['chill.main.form.type.translatable.string'] = new \Chill\MainBundle\Form\Type\TranslatableStringFormType(array(0 => 'fr'), $this->get('translator.default')); + return $this->services['chill.main.form.type.translatable.string'] = new \Chill\MainBundle\Form\Type\TranslatableStringFormType([0 => 'fr'], $this->get('translator.default')); } /** @@ -701,7 +755,7 @@ class appDevDebugProjectContainer extends Container */ protected function getChill_Main_RoutesLoaderService() { - return $this->services['chill.main.routes_loader'] = new \Chill\MainBundle\Routing\Loader\ChillRoutesLoader(array(0 => '@ChillPersonBundle/Resources/config/routing.yml', 1 => '@ChillCustomFieldsBundle/Resources/config/routing.yml', 2 => '@ChillMainBundle/Resources/config/routing.yml')); + return $this->services['chill.main.routes_loader'] = new \Chill\MainBundle\Routing\Loader\ChillRoutesLoader([0 => '@ChillPersonBundle/Resources/config/routing.yml', 1 => '@ChillCustomFieldsBundle/Resources/config/routing.yml', 2 => '@ChillMainBundle/Resources/config/routing.yml']); } /** @@ -806,9 +860,9 @@ class appDevDebugProjectContainer extends Container * This service is shared. * This method always returns the same instance of the service. * - * @return \Chill\PersonBundle\Form\Type\ClosingMotiveType A Chill\PersonBundle\Form\Type\ClosingMotiveType instance. - * * @throws InactiveScopeException when the 'chill.person.accompanying_period_closing_motive' service is requested while the 'request' scope is not active + * + * @return \Chill\PersonBundle\Form\Type\ClosingMotiveType A Chill\PersonBundle\Form\Type\ClosingMotiveType instance. */ protected function getChill_Person_AccompanyingPeriodClosingMotiveService() { @@ -875,6 +929,23 @@ class appDevDebugProjectContainer extends Container return $this->services['chill.person.timeline.accompanying_period_opening'] = new \Chill\PersonBundle\Timeline\TimelineAccompanyingPeriodOpening($this->get('doctrine.orm.default_entity_manager')); } + /** + * Gets the 'controller_name_converter' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser A Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser instance. + */ + protected function getControllerNameConverterService() + { + return $this->services['controller_name_converter'] = new \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser($this->get('kernel')); + } + /** * Gets the 'data_collector.dump' service. * @@ -885,20 +956,7 @@ class appDevDebugProjectContainer extends Container */ protected function getDataCollector_DumpService() { - return $this->services['data_collector.dump'] = new \Symfony\Component\HttpKernel\DataCollector\DumpDataCollector($this->get('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE), NULL, 'UTF-8', NULL, NULL); - } - - /** - * Gets the 'data_collector.form' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Form\Extension\DataCollector\FormDataCollector A Symfony\Component\Form\Extension\DataCollector\FormDataCollector instance. - */ - protected function getDataCollector_FormService() - { - return $this->services['data_collector.form'] = new \Symfony\Component\Form\Extension\DataCollector\FormDataCollector($this->get('data_collector.form.extractor')); + return $this->services['data_collector.dump'] = new \Symfony\Component\HttpKernel\DataCollector\DumpDataCollector($this->get('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE), null, 'UTF-8', null, null); } /** @@ -914,6 +972,19 @@ class appDevDebugProjectContainer extends Container return $this->services['data_collector.form.extractor'] = new \Symfony\Component\Form\Extension\DataCollector\FormDataExtractor(); } + /** + * Gets the 'data_collector.form' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\Form\Extension\DataCollector\FormDataCollector A Symfony\Component\Form\Extension\DataCollector\FormDataCollector instance. + */ + protected function getDataCollector_FormService() + { + return $this->services['data_collector.form'] = new \Symfony\Component\Form\Extension\DataCollector\FormDataCollector($this->get('data_collector.form.extractor')); + } + /** * Gets the 'data_collector.request' service. * @@ -976,7 +1047,7 @@ class appDevDebugProjectContainer extends Container */ protected function getDebug_DebugHandlersListenerService() { - return $this->services['debug.debug_handlers_listener'] = new \Symfony\Component\HttpKernel\EventListener\DebugHandlersListener('', $this->get('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), NULL, NULL, true, NULL); + return $this->services['debug.debug_handlers_listener'] = new \Symfony\Component\HttpKernel\EventListener\DebugHandlersListener('', $this->get('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), null, null, true, null); } /** @@ -1004,7 +1075,7 @@ class appDevDebugProjectContainer extends Container { $this->services['debug.event_dispatcher'] = $instance = new \Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher(new \Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher($this), $this->get('debug.stopwatch'), $this->get('monolog.logger.event', ContainerInterface::NULL_ON_INVALID_REFERENCE)); - $instance->addListenerService('kernel.controller', array(0 => 'data_collector.router', 1 => 'onKernelController'), 0); + $instance->addListenerService('kernel.controller', [0 => 'data_collector.router', 1 => 'onKernelController'], 0); $instance->addSubscriberService('response_listener', 'Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener'); $instance->addSubscriberService('streamed_response_listener', 'Symfony\\Component\\HttpKernel\\EventListener\\StreamedResponseListener'); $instance->addSubscriberService('locale_listener', 'Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener'); @@ -1044,16 +1115,648 @@ class appDevDebugProjectContainer extends Container } /** - * Gets the 'doctrine' service. + * Gets the default parameters. * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Doctrine\Bundle\DoctrineBundle\Registry A Doctrine\Bundle\DoctrineBundle\Registry instance. + * @return array An array of the default parameters */ - protected function getDoctrineService() + protected function getDefaultParameters() { - return $this->services['doctrine'] = new \Doctrine\Bundle\DoctrineBundle\Registry($this, array('default' => 'doctrine.dbal.default_connection'), array('default' => 'doctrine.orm.default_entity_manager'), 'default', 'default'); + return [ + 'kernel.root_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app', + 'kernel.environment' => 'dev', + 'kernel.debug' => true, + 'kernel.name' => 'app', + 'kernel.cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev', + 'kernel.logs_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/logs', + 'kernel.bundles' => [ + 'FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle', + 'SecurityBundle' => 'Symfony\\Bundle\\SecurityBundle\\SecurityBundle', + 'TwigBundle' => 'Symfony\\Bundle\\TwigBundle\\TwigBundle', + 'MonologBundle' => 'Symfony\\Bundle\\MonologBundle\\MonologBundle', + 'SwiftmailerBundle' => 'Symfony\\Bundle\\SwiftmailerBundle\\SwiftmailerBundle', + 'AsseticBundle' => 'Symfony\\Bundle\\AsseticBundle\\AsseticBundle', + 'DoctrineBundle' => 'Doctrine\\Bundle\\DoctrineBundle\\DoctrineBundle', + 'SensioFrameworkExtraBundle' => 'Sensio\\Bundle\\FrameworkExtraBundle\\SensioFrameworkExtraBundle', + 'ChillMainBundle' => 'Chill\\MainBundle\\ChillMainBundle', + 'ChillCustomFieldsBundle' => 'Chill\\CustomFieldsBundle\\ChillCustomFieldsBundle', + 'ChillPersonBundle' => 'Chill\\PersonBundle\\ChillPersonBundle', + 'ChillActivityBundle' => 'Chill\\ActivityBundle\\ChillActivityBundle', + 'DebugBundle' => 'Symfony\\Bundle\\DebugBundle\\DebugBundle', + 'WebProfilerBundle' => 'Symfony\\Bundle\\WebProfilerBundle\\WebProfilerBundle', + 'SensioDistributionBundle' => 'Sensio\\Bundle\\DistributionBundle\\SensioDistributionBundle', + 'SensioGeneratorBundle' => 'Sensio\\Bundle\\GeneratorBundle\\SensioGeneratorBundle', + ], + 'kernel.charset' => 'UTF-8', + 'kernel.container_class' => 'appDevDebugProjectContainer', + 'database_host' => '127.0.0.1', + 'database_port' => 5432, + 'database_name' => 'chill_test', + 'database_user' => 'chill', + 'database_password' => 'chill', + 'locale' => 'fr', + 'controller_resolver.class' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver', + 'controller_name_converter.class' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerNameParser', + 'response_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener', + 'streamed_response_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\StreamedResponseListener', + 'locale_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener', + 'event_dispatcher.class' => 'Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher', + 'http_kernel.class' => 'Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel', + 'filesystem.class' => 'Symfony\\Component\\Filesystem\\Filesystem', + 'cache_warmer.class' => 'Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerAggregate', + 'cache_clearer.class' => 'Symfony\\Component\\HttpKernel\\CacheClearer\\ChainCacheClearer', + 'file_locator.class' => 'Symfony\\Component\\HttpKernel\\Config\\FileLocator', + 'uri_signer.class' => 'Symfony\\Component\\HttpKernel\\UriSigner', + 'request_stack.class' => 'Symfony\\Component\\HttpFoundation\\RequestStack', + 'fragment.handler.class' => 'Symfony\\Component\\HttpKernel\\DependencyInjection\\LazyLoadingFragmentHandler', + 'fragment.renderer.inline.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\InlineFragmentRenderer', + 'fragment.renderer.hinclude.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\HIncludeFragmentRenderer', + 'fragment.renderer.hinclude.global_template' => null, + 'fragment.renderer.esi.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\EsiFragmentRenderer', + 'fragment.path' => '/_fragment', + 'translator.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\Translator', + 'translator.identity.class' => 'Symfony\\Component\\Translation\\IdentityTranslator', + 'translator.selector.class' => 'Symfony\\Component\\Translation\\MessageSelector', + 'translation.loader.php.class' => 'Symfony\\Component\\Translation\\Loader\\PhpFileLoader', + 'translation.loader.yml.class' => 'Symfony\\Component\\Translation\\Loader\\YamlFileLoader', + 'translation.loader.xliff.class' => 'Symfony\\Component\\Translation\\Loader\\XliffFileLoader', + 'translation.loader.po.class' => 'Symfony\\Component\\Translation\\Loader\\PoFileLoader', + 'translation.loader.mo.class' => 'Symfony\\Component\\Translation\\Loader\\MoFileLoader', + 'translation.loader.qt.class' => 'Symfony\\Component\\Translation\\Loader\\QtFileLoader', + 'translation.loader.csv.class' => 'Symfony\\Component\\Translation\\Loader\\CsvFileLoader', + 'translation.loader.res.class' => 'Symfony\\Component\\Translation\\Loader\\IcuResFileLoader', + 'translation.loader.dat.class' => 'Symfony\\Component\\Translation\\Loader\\IcuDatFileLoader', + 'translation.loader.ini.class' => 'Symfony\\Component\\Translation\\Loader\\IniFileLoader', + 'translation.loader.json.class' => 'Symfony\\Component\\Translation\\Loader\\JsonFileLoader', + 'translation.dumper.php.class' => 'Symfony\\Component\\Translation\\Dumper\\PhpFileDumper', + 'translation.dumper.xliff.class' => 'Symfony\\Component\\Translation\\Dumper\\XliffFileDumper', + 'translation.dumper.po.class' => 'Symfony\\Component\\Translation\\Dumper\\PoFileDumper', + 'translation.dumper.mo.class' => 'Symfony\\Component\\Translation\\Dumper\\MoFileDumper', + 'translation.dumper.yml.class' => 'Symfony\\Component\\Translation\\Dumper\\YamlFileDumper', + 'translation.dumper.qt.class' => 'Symfony\\Component\\Translation\\Dumper\\QtFileDumper', + 'translation.dumper.csv.class' => 'Symfony\\Component\\Translation\\Dumper\\CsvFileDumper', + 'translation.dumper.ini.class' => 'Symfony\\Component\\Translation\\Dumper\\IniFileDumper', + 'translation.dumper.json.class' => 'Symfony\\Component\\Translation\\Dumper\\JsonFileDumper', + 'translation.dumper.res.class' => 'Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper', + 'translation.extractor.php.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\PhpExtractor', + 'translation.loader.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\TranslationLoader', + 'translation.extractor.class' => 'Symfony\\Component\\Translation\\Extractor\\ChainExtractor', + 'translation.writer.class' => 'Symfony\\Component\\Translation\\Writer\\TranslationWriter', + 'property_accessor.class' => 'Symfony\\Component\\PropertyAccess\\PropertyAccessor', + 'kernel.secret' => 'Not very secret', + 'kernel.http_method_override' => true, + 'kernel.trusted_hosts' => [ + ], + 'kernel.trusted_proxies' => [ + ], + 'kernel.default_locale' => 'fr', + 'test.client.class' => 'Symfony\\Bundle\\FrameworkBundle\\Client', + 'test.client.parameters' => [ + ], + 'test.client.history.class' => 'Symfony\\Component\\BrowserKit\\History', + 'test.client.cookiejar.class' => 'Symfony\\Component\\BrowserKit\\CookieJar', + 'test.session.listener.class' => 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\TestSessionListener', + 'session.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Session', + 'session.flashbag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBag', + 'session.attribute_bag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag', + 'session.storage.metadata_bag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\MetadataBag', + 'session.metadata.storage_key' => '_sf2_meta', + 'session.storage.native.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage', + 'session.storage.php_bridge.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\PhpBridgeSessionStorage', + 'session.storage.mock_file.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockFileSessionStorage', + 'session.handler.native_file.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeFileSessionHandler', + 'session.handler.write_check.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\WriteCheckSessionHandler', + 'session_listener.class' => 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener', + 'session.storage.options' => [ + 'gc_probability' => 1, + ], + 'session.save_path' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/sessions', + 'session.metadata.update_threshold' => '0', + 'security.secure_random.class' => 'Symfony\\Component\\Security\\Core\\Util\\SecureRandom', + 'form.resolved_type_factory.class' => 'Symfony\\Component\\Form\\ResolvedFormTypeFactory', + 'form.registry.class' => 'Symfony\\Component\\Form\\FormRegistry', + 'form.factory.class' => 'Symfony\\Component\\Form\\FormFactory', + 'form.extension.class' => 'Symfony\\Component\\Form\\Extension\\DependencyInjection\\DependencyInjectionExtension', + 'form.type_guesser.validator.class' => 'Symfony\\Component\\Form\\Extension\\Validator\\ValidatorTypeGuesser', + 'form.type_extension.form.request_handler.class' => 'Symfony\\Component\\Form\\Extension\\HttpFoundation\\HttpFoundationRequestHandler', + 'form.type_extension.csrf.enabled' => true, + 'form.type_extension.csrf.field_name' => '_token', + 'security.csrf.token_generator.class' => 'Symfony\\Component\\Security\\Csrf\\TokenGenerator\\UriSafeTokenGenerator', + 'security.csrf.token_storage.class' => 'Symfony\\Component\\Security\\Csrf\\TokenStorage\\SessionTokenStorage', + 'security.csrf.token_manager.class' => 'Symfony\\Component\\Security\\Csrf\\CsrfTokenManager', + 'templating.engine.delegating.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\DelegatingEngine', + 'templating.name_parser.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateNameParser', + 'templating.filename_parser.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateFilenameParser', + 'templating.cache_warmer.template_paths.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\TemplatePathsCacheWarmer', + 'templating.locator.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\TemplateLocator', + 'templating.loader.filesystem.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\FilesystemLoader', + 'templating.loader.cache.class' => 'Symfony\\Component\\Templating\\Loader\\CacheLoader', + 'templating.loader.chain.class' => 'Symfony\\Component\\Templating\\Loader\\ChainLoader', + 'templating.finder.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\TemplateFinder', + 'templating.helper.assets.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\AssetsHelper', + 'templating.helper.router.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\RouterHelper', + 'templating.helper.code.file_link_format' => null, + 'templating.loader.cache.path' => null, + 'templating.engines' => [ + 0 => 'twig', + ], + 'validator.class' => 'Symfony\\Component\\Validator\\Validator\\ValidatorInterface', + 'validator.builder.class' => 'Symfony\\Component\\Validator\\ValidatorBuilderInterface', + 'validator.builder.factory.class' => 'Symfony\\Component\\Validator\\Validation', + 'validator.mapping.cache.apc.class' => 'Symfony\\Component\\Validator\\Mapping\\Cache\\ApcCache', + 'validator.mapping.cache.prefix' => '', + 'validator.validator_factory.class' => 'Symfony\\Bundle\\FrameworkBundle\\Validator\\ConstraintValidatorFactory', + 'validator.expression.class' => 'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator', + 'validator.email.class' => 'Symfony\\Component\\Validator\\Constraints\\EmailValidator', + 'validator.translation_domain' => 'validators', + 'validator.api' => '2.5-bc', + 'translator.logging' => true, + 'profiler.class' => 'Symfony\\Component\\HttpKernel\\Profiler\\Profiler', + 'profiler_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ProfilerListener', + 'data_collector.config.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\ConfigDataCollector', + 'data_collector.request.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector', + 'data_collector.exception.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\ExceptionDataCollector', + 'data_collector.events.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\EventDataCollector', + 'data_collector.logger.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\LoggerDataCollector', + 'data_collector.time.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\TimeDataCollector', + 'data_collector.memory.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\MemoryDataCollector', + 'data_collector.router.class' => 'Symfony\\Bundle\\FrameworkBundle\\DataCollector\\RouterDataCollector', + 'form.resolved_type_factory.data_collector_proxy.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\Proxy\\ResolvedTypeFactoryDataCollectorProxy', + 'form.type_extension.form.data_collector.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\Type\\DataCollectorTypeExtension', + 'data_collector.form.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\FormDataCollector', + 'data_collector.form.extractor.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\FormDataExtractor', + 'profiler_listener.only_exceptions' => false, + 'profiler_listener.only_master_requests' => false, + 'profiler.storage.dsn' => 'file:/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/profiler', + 'profiler.storage.username' => '', + 'profiler.storage.password' => '', + 'profiler.storage.lifetime' => 86400, + 'router.class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\Router', + 'router.request_context.class' => 'Symfony\\Component\\Routing\\RequestContext', + 'routing.loader.class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader', + 'routing.resolver.class' => 'Symfony\\Component\\Config\\Loader\\LoaderResolver', + 'routing.loader.xml.class' => 'Symfony\\Component\\Routing\\Loader\\XmlFileLoader', + 'routing.loader.yml.class' => 'Symfony\\Component\\Routing\\Loader\\YamlFileLoader', + 'routing.loader.php.class' => 'Symfony\\Component\\Routing\\Loader\\PhpFileLoader', + 'router.options.generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', + 'router.options.generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', + 'router.options.generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', + 'router.options.matcher_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', + 'router.options.matcher_base_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', + 'router.options.matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', + 'router.cache_warmer.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\RouterCacheWarmer', + 'router.options.matcher.cache_class' => 'appDevUrlMatcher', + 'router.options.generator.cache_class' => 'appDevUrlGenerator', + 'router_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\RouterListener', + 'router.request_context.host' => 'localhost', + 'router.request_context.scheme' => 'http', + 'router.request_context.base_url' => '', + 'router.resource' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/config/routing.yml', + 'router.cache_class_prefix' => 'appDev', + 'request_listener.http_port' => 80, + 'request_listener.https_port' => 443, + 'annotations.reader.class' => 'Doctrine\\Common\\Annotations\\AnnotationReader', + 'annotations.cached_reader.class' => 'Doctrine\\Common\\Annotations\\CachedReader', + 'annotations.file_cache_reader.class' => 'Doctrine\\Common\\Annotations\\FileCacheReader', + 'debug.debug_handlers_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener', + 'debug.stopwatch.class' => 'Symfony\\Component\\Stopwatch\\Stopwatch', + 'debug.error_handler.throw_at' => -1, + 'debug.event_dispatcher.class' => 'Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher', + 'debug.container.dump' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/appDevDebugProjectContainer.xml', + 'debug.controller_resolver.class' => 'Symfony\\Component\\HttpKernel\\Controller\\TraceableControllerResolver', + 'security.context.class' => 'Symfony\\Component\\Security\\Core\\SecurityContext', + 'security.user_checker.class' => 'Symfony\\Component\\Security\\Core\\User\\UserChecker', + 'security.encoder_factory.generic.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\EncoderFactory', + 'security.encoder.digest.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\MessageDigestPasswordEncoder', + 'security.encoder.plain.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\PlaintextPasswordEncoder', + 'security.encoder.pbkdf2.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\Pbkdf2PasswordEncoder', + 'security.encoder.bcrypt.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\BCryptPasswordEncoder', + 'security.user.provider.in_memory.class' => 'Symfony\\Component\\Security\\Core\\User\\InMemoryUserProvider', + 'security.user.provider.in_memory.user.class' => 'Symfony\\Component\\Security\\Core\\User\\User', + 'security.user.provider.chain.class' => 'Symfony\\Component\\Security\\Core\\User\\ChainUserProvider', + 'security.authentication.trust_resolver.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolver', + 'security.authentication.trust_resolver.anonymous_class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken', + 'security.authentication.trust_resolver.rememberme_class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken', + 'security.authentication.manager.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationProviderManager', + 'security.authentication.session_strategy.class' => 'Symfony\\Component\\Security\\Http\\Session\\SessionAuthenticationStrategy', + 'security.access.decision_manager.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager', + 'security.access.simple_role_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter', + 'security.access.authenticated_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AuthenticatedVoter', + 'security.access.role_hierarchy_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleHierarchyVoter', + 'security.access.expression_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\ExpressionVoter', + 'security.firewall.class' => 'Symfony\\Component\\Security\\Http\\Firewall', + 'security.firewall.map.class' => 'Symfony\\Bundle\\SecurityBundle\\Security\\FirewallMap', + 'security.firewall.context.class' => 'Symfony\\Bundle\\SecurityBundle\\Security\\FirewallContext', + 'security.matcher.class' => 'Symfony\\Component\\HttpFoundation\\RequestMatcher', + 'security.expression_matcher.class' => 'Symfony\\Component\\HttpFoundation\\ExpressionRequestMatcher', + 'security.role_hierarchy.class' => 'Symfony\\Component\\Security\\Core\\Role\\RoleHierarchy', + 'security.http_utils.class' => 'Symfony\\Component\\Security\\Http\\HttpUtils', + 'security.validator.user_password.class' => 'Symfony\\Component\\Security\\Core\\Validator\\Constraints\\UserPasswordValidator', + 'security.expression_language.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\ExpressionLanguage', + 'security.authentication.retry_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\RetryAuthenticationEntryPoint', + 'security.channel_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ChannelListener', + 'security.authentication.form_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\FormAuthenticationEntryPoint', + 'security.authentication.listener.form.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\UsernamePasswordFormAuthenticationListener', + 'security.authentication.listener.simple_form.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SimpleFormAuthenticationListener', + 'security.authentication.listener.simple_preauth.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SimplePreAuthenticationListener', + 'security.authentication.listener.basic.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\BasicAuthenticationListener', + 'security.authentication.basic_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\BasicAuthenticationEntryPoint', + 'security.authentication.listener.digest.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\DigestAuthenticationListener', + 'security.authentication.digest_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\DigestAuthenticationEntryPoint', + 'security.authentication.listener.x509.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\X509AuthenticationListener', + 'security.authentication.listener.anonymous.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\AnonymousAuthenticationListener', + 'security.authentication.switchuser_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SwitchUserListener', + 'security.logout_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\LogoutListener', + 'security.logout.handler.session.class' => 'Symfony\\Component\\Security\\Http\\Logout\\SessionLogoutHandler', + 'security.logout.handler.cookie_clearing.class' => 'Symfony\\Component\\Security\\Http\\Logout\\CookieClearingLogoutHandler', + 'security.logout.success_handler.class' => 'Symfony\\Component\\Security\\Http\\Logout\\DefaultLogoutSuccessHandler', + 'security.access_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\AccessListener', + 'security.access_map.class' => 'Symfony\\Component\\Security\\Http\\AccessMap', + 'security.exception_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ExceptionListener', + 'security.context_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ContextListener', + 'security.authentication.provider.dao.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider', + 'security.authentication.provider.simple.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\SimpleAuthenticationProvider', + 'security.authentication.provider.pre_authenticated.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\PreAuthenticatedAuthenticationProvider', + 'security.authentication.provider.anonymous.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AnonymousAuthenticationProvider', + 'security.authentication.success_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\DefaultAuthenticationSuccessHandler', + 'security.authentication.failure_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\DefaultAuthenticationFailureHandler', + 'security.authentication.simple_success_failure_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\SimpleAuthenticationHandler', + 'security.authentication.provider.rememberme.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\RememberMeAuthenticationProvider', + 'security.authentication.listener.rememberme.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\RememberMeListener', + 'security.rememberme.token.provider.in_memory.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\RememberMe\\InMemoryTokenProvider', + 'security.authentication.rememberme.services.persistent.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\PersistentTokenBasedRememberMeServices', + 'security.authentication.rememberme.services.simplehash.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\TokenBasedRememberMeServices', + 'security.rememberme.response_listener.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\ResponseListener', + 'templating.helper.logout_url.class' => 'Symfony\\Bundle\\SecurityBundle\\Templating\\Helper\\LogoutUrlHelper', + 'templating.helper.security.class' => 'Symfony\\Bundle\\SecurityBundle\\Templating\\Helper\\SecurityHelper', + 'twig.extension.logout_url.class' => 'Symfony\\Bridge\\Twig\\Extension\\LogoutUrlExtension', + 'twig.extension.security.class' => 'Symfony\\Bridge\\Twig\\Extension\\SecurityExtension', + 'data_collector.security.class' => 'Symfony\\Bundle\\SecurityBundle\\DataCollector\\SecurityDataCollector', + 'security.access.denied_url' => null, + 'security.authentication.manager.erase_credentials' => true, + 'security.authentication.session_strategy.strategy' => 'migrate', + 'security.access.always_authenticate_before_granting' => false, + 'security.authentication.hide_user_not_found' => true, + 'security.role_hierarchy.roles' => [ + 'CHILL_PERSON_UPDATE' => [ + 0 => 'CHILL_PERSON_SEE', + ], + 'CHILL_PERSON_CREATE' => [ + 0 => 'CHILL_PERSON_SEE', + ], + ], + 'twig.class' => 'Twig_Environment', + 'twig.loader.filesystem.class' => 'Symfony\\Bundle\\TwigBundle\\Loader\\FilesystemLoader', + 'twig.loader.chain.class' => 'Twig_Loader_Chain', + 'templating.engine.twig.class' => 'Symfony\\Bundle\\TwigBundle\\TwigEngine', + 'twig.cache_warmer.class' => 'Symfony\\Bundle\\TwigBundle\\CacheWarmer\\TemplateCacheCacheWarmer', + 'twig.extension.trans.class' => 'Symfony\\Bridge\\Twig\\Extension\\TranslationExtension', + 'twig.extension.actions.class' => 'Symfony\\Bundle\\TwigBundle\\Extension\\ActionsExtension', + 'twig.extension.code.class' => 'Symfony\\Bridge\\Twig\\Extension\\CodeExtension', + 'twig.extension.routing.class' => 'Symfony\\Bridge\\Twig\\Extension\\RoutingExtension', + 'twig.extension.yaml.class' => 'Symfony\\Bridge\\Twig\\Extension\\YamlExtension', + 'twig.extension.form.class' => 'Symfony\\Bridge\\Twig\\Extension\\FormExtension', + 'twig.extension.httpkernel.class' => 'Symfony\\Bridge\\Twig\\Extension\\HttpKernelExtension', + 'twig.extension.debug.stopwatch.class' => 'Symfony\\Bridge\\Twig\\Extension\\StopwatchExtension', + 'twig.extension.expression.class' => 'Symfony\\Bridge\\Twig\\Extension\\ExpressionExtension', + 'twig.form.engine.class' => 'Symfony\\Bridge\\Twig\\Form\\TwigRendererEngine', + 'twig.form.renderer.class' => 'Symfony\\Bridge\\Twig\\Form\\TwigRenderer', + 'twig.translation.extractor.class' => 'Symfony\\Bridge\\Twig\\Translation\\TwigExtractor', + 'twig.exception_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ExceptionListener', + 'twig.controller.exception.class' => 'Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController', + 'twig.controller.preview_error.class' => 'Symfony\\Bundle\\TwigBundle\\Controller\\PreviewErrorController', + 'twig.exception_listener.controller' => 'twig.controller.exception:showAction', + 'twig.form.resources' => [ + 0 => 'form_div_layout.html.twig', + 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', + 2 => 'ChillMainBundle:Form:fields.html.twig', + ], + 'monolog.logger.class' => 'Symfony\\Bridge\\Monolog\\Logger', + 'monolog.gelf.publisher.class' => 'Gelf\\MessagePublisher', + 'monolog.gelfphp.publisher.class' => 'Gelf\\Publisher', + 'monolog.handler.stream.class' => 'Monolog\\Handler\\StreamHandler', + 'monolog.handler.console.class' => 'Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler', + 'monolog.handler.group.class' => 'Monolog\\Handler\\GroupHandler', + 'monolog.handler.buffer.class' => 'Monolog\\Handler\\BufferHandler', + 'monolog.handler.rotating_file.class' => 'Monolog\\Handler\\RotatingFileHandler', + 'monolog.handler.syslog.class' => 'Monolog\\Handler\\SyslogHandler', + 'monolog.handler.syslogudp.class' => 'Monolog\\Handler\\SyslogUdpHandler', + 'monolog.handler.null.class' => 'Monolog\\Handler\\NullHandler', + 'monolog.handler.test.class' => 'Monolog\\Handler\\TestHandler', + 'monolog.handler.gelf.class' => 'Monolog\\Handler\\GelfHandler', + 'monolog.handler.rollbar.class' => 'Monolog\\Handler\\RollbarHandler', + 'monolog.handler.flowdock.class' => 'Monolog\\Handler\\FlowdockHandler', + 'monolog.handler.browser_console.class' => 'Monolog\\Handler\\BrowserConsoleHandler', + 'monolog.handler.firephp.class' => 'Symfony\\Bridge\\Monolog\\Handler\\FirePHPHandler', + 'monolog.handler.chromephp.class' => 'Symfony\\Bridge\\Monolog\\Handler\\ChromePhpHandler', + 'monolog.handler.debug.class' => 'Symfony\\Bridge\\Monolog\\Handler\\DebugHandler', + 'monolog.handler.swift_mailer.class' => 'Symfony\\Bridge\\Monolog\\Handler\\SwiftMailerHandler', + 'monolog.handler.native_mailer.class' => 'Monolog\\Handler\\NativeMailerHandler', + 'monolog.handler.socket.class' => 'Monolog\\Handler\\SocketHandler', + 'monolog.handler.pushover.class' => 'Monolog\\Handler\\PushoverHandler', + 'monolog.handler.raven.class' => 'Monolog\\Handler\\RavenHandler', + 'monolog.handler.newrelic.class' => 'Monolog\\Handler\\NewRelicHandler', + 'monolog.handler.hipchat.class' => 'Monolog\\Handler\\HipChatHandler', + 'monolog.handler.slack.class' => 'Monolog\\Handler\\SlackHandler', + 'monolog.handler.cube.class' => 'Monolog\\Handler\\CubeHandler', + 'monolog.handler.amqp.class' => 'Monolog\\Handler\\AmqpHandler', + 'monolog.handler.error_log.class' => 'Monolog\\Handler\\ErrorLogHandler', + 'monolog.handler.loggly.class' => 'Monolog\\Handler\\LogglyHandler', + 'monolog.handler.logentries.class' => 'Monolog\\Handler\\LogEntriesHandler', + 'monolog.handler.whatfailuregroup.class' => 'Monolog\\Handler\\WhatFailureGroupHandler', + 'monolog.activation_strategy.not_found.class' => 'Symfony\\Bundle\\MonologBundle\\NotFoundActivationStrategy', + 'monolog.handler.fingers_crossed.class' => 'Monolog\\Handler\\FingersCrossedHandler', + 'monolog.handler.fingers_crossed.error_level_activation_strategy.class' => 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy', + 'monolog.handler.filter.class' => 'Monolog\\Handler\\FilterHandler', + 'monolog.handler.mongo.class' => 'Monolog\\Handler\\MongoDBHandler', + 'monolog.mongo.client.class' => 'MongoClient', + 'monolog.handler.elasticsearch.class' => 'Monolog\\Handler\\ElasticSearchHandler', + 'monolog.elastica.client.class' => 'Elastica\\Client', + 'monolog.swift_mailer.handlers' => [ + ], + 'monolog.handlers_to_channels' => [ + ], + 'swiftmailer.class' => 'Swift_Mailer', + 'swiftmailer.transport.sendmail.class' => 'Swift_Transport_SendmailTransport', + 'swiftmailer.transport.mail.class' => 'Swift_Transport_MailTransport', + 'swiftmailer.transport.failover.class' => 'Swift_Transport_FailoverTransport', + 'swiftmailer.plugin.redirecting.class' => 'Swift_Plugins_RedirectingPlugin', + 'swiftmailer.plugin.impersonate.class' => 'Swift_Plugins_ImpersonatePlugin', + 'swiftmailer.plugin.messagelogger.class' => 'Swift_Plugins_MessageLogger', + 'swiftmailer.plugin.antiflood.class' => 'Swift_Plugins_AntiFloodPlugin', + 'swiftmailer.transport.smtp.class' => 'Swift_Transport_EsmtpTransport', + 'swiftmailer.plugin.blackhole.class' => 'Swift_Plugins_BlackholePlugin', + 'swiftmailer.spool.file.class' => 'Swift_FileSpool', + 'swiftmailer.spool.memory.class' => 'Swift_MemorySpool', + 'swiftmailer.email_sender.listener.class' => 'Symfony\\Bundle\\SwiftmailerBundle\\EventListener\\EmailSenderListener', + 'swiftmailer.data_collector.class' => 'Symfony\\Bundle\\SwiftmailerBundle\\DataCollector\\MessageDataCollector', + 'swiftmailer.mailer.default.transport.name' => 'smtp', + 'swiftmailer.mailer.default.delivery.enabled' => true, + 'swiftmailer.mailer.default.transport.smtp.encryption' => null, + 'swiftmailer.mailer.default.transport.smtp.port' => 25, + 'swiftmailer.mailer.default.transport.smtp.host' => 'localhost', + 'swiftmailer.mailer.default.transport.smtp.username' => null, + 'swiftmailer.mailer.default.transport.smtp.password' => null, + 'swiftmailer.mailer.default.transport.smtp.auth_mode' => null, + 'swiftmailer.mailer.default.transport.smtp.timeout' => 30, + 'swiftmailer.mailer.default.transport.smtp.source_ip' => null, + 'swiftmailer.mailer.default.spool.enabled' => false, + 'swiftmailer.mailer.default.plugin.impersonate' => null, + 'swiftmailer.mailer.default.single_address' => null, + 'swiftmailer.spool.enabled' => false, + 'swiftmailer.delivery.enabled' => true, + 'swiftmailer.single_address' => null, + 'swiftmailer.mailers' => [ + 'default' => 'swiftmailer.mailer.default', + ], + 'swiftmailer.default_mailer' => 'default', + 'assetic.asset_factory.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\AssetFactory', + 'assetic.asset_manager.class' => 'Assetic\\Factory\\LazyAssetManager', + 'assetic.asset_manager_cache_warmer.class' => 'Symfony\\Bundle\\AsseticBundle\\CacheWarmer\\AssetManagerCacheWarmer', + 'assetic.cached_formula_loader.class' => 'Assetic\\Factory\\Loader\\CachedFormulaLoader', + 'assetic.config_cache.class' => 'Assetic\\Cache\\ConfigCache', + 'assetic.config_loader.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Loader\\ConfigurationLoader', + 'assetic.config_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\ConfigurationResource', + 'assetic.coalescing_directory_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\CoalescingDirectoryResource', + 'assetic.directory_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\DirectoryResource', + 'assetic.filter_manager.class' => 'Symfony\\Bundle\\AsseticBundle\\FilterManager', + 'assetic.worker.ensure_filter.class' => 'Assetic\\Factory\\Worker\\EnsureFilterWorker', + 'assetic.worker.cache_busting.class' => 'Assetic\\Factory\\Worker\\CacheBustingWorker', + 'assetic.value_supplier.class' => 'Symfony\\Bundle\\AsseticBundle\\DefaultValueSupplier', + 'assetic.node.paths' => [ + ], + 'assetic.cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/assetic', + 'assetic.bundles' => [ + 0 => 'ChillPersonBundle', + 1 => 'ChillMainBundle', + ], + 'assetic.twig_extension.class' => 'Symfony\\Bundle\\AsseticBundle\\Twig\\AsseticExtension', + 'assetic.twig_formula_loader.class' => 'Assetic\\Extension\\Twig\\TwigFormulaLoader', + 'assetic.helper.dynamic.class' => 'Symfony\\Bundle\\AsseticBundle\\Templating\\DynamicAsseticHelper', + 'assetic.helper.static.class' => 'Symfony\\Bundle\\AsseticBundle\\Templating\\StaticAsseticHelper', + 'assetic.php_formula_loader.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Loader\\AsseticHelperFormulaLoader', + 'assetic.debug' => true, + 'assetic.use_controller' => false, + 'assetic.enable_profiler' => false, + 'assetic.read_from' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', + 'assetic.write_to' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', + 'assetic.variables' => [ + ], + 'assetic.java.bin' => '/usr/bin/java', + 'assetic.node.bin' => '/usr/local/bin/node', + 'assetic.ruby.bin' => '/usr/local/opt/ruby/bin/ruby', + 'assetic.sass.bin' => '/usr/local/bin/sass', + 'assetic.filter.cssrewrite.class' => 'Assetic\\Filter\\CssRewriteFilter', + 'assetic.twig_extension.functions' => [ + ], + 'doctrine_cache.apc.class' => 'Doctrine\\Common\\Cache\\ApcCache', + 'doctrine_cache.array.class' => 'Doctrine\\Common\\Cache\\ArrayCache', + 'doctrine_cache.file_system.class' => 'Doctrine\\Common\\Cache\\FilesystemCache', + 'doctrine_cache.php_file.class' => 'Doctrine\\Common\\Cache\\PhpFileCache', + 'doctrine_cache.mongodb.class' => 'Doctrine\\Common\\Cache\\MongoDBCache', + 'doctrine_cache.mongodb.collection.class' => 'MongoCollection', + 'doctrine_cache.mongodb.connection.class' => 'MongoClient', + 'doctrine_cache.mongodb.server' => 'localhost:27017', + 'doctrine_cache.riak.class' => 'Doctrine\\Common\\Cache\\RiakCache', + 'doctrine_cache.riak.bucket.class' => 'Riak\\Bucket', + 'doctrine_cache.riak.connection.class' => 'Riak\\Connection', + 'doctrine_cache.riak.bucket_property_list.class' => 'Riak\\BucketPropertyList', + 'doctrine_cache.riak.host' => 'localhost', + 'doctrine_cache.riak.port' => 8087, + 'doctrine_cache.memcache.class' => 'Doctrine\\Common\\Cache\\MemcacheCache', + 'doctrine_cache.memcache.connection.class' => 'Memcache', + 'doctrine_cache.memcache.host' => 'localhost', + 'doctrine_cache.memcache.port' => 11211, + 'doctrine_cache.memcached.class' => 'Doctrine\\Common\\Cache\\MemcachedCache', + 'doctrine_cache.memcached.connection.class' => 'Memcached', + 'doctrine_cache.memcached.host' => 'localhost', + 'doctrine_cache.memcached.port' => 11211, + 'doctrine_cache.redis.class' => 'Doctrine\\Common\\Cache\\RedisCache', + 'doctrine_cache.redis.connection.class' => 'Redis', + 'doctrine_cache.redis.host' => 'localhost', + 'doctrine_cache.redis.port' => 6379, + 'doctrine_cache.couchbase.class' => 'Doctrine\\Common\\Cache\\CouchbaseCache', + 'doctrine_cache.couchbase.connection.class' => 'Couchbase', + 'doctrine_cache.couchbase.hostnames' => 'localhost:8091', + 'doctrine_cache.wincache.class' => 'Doctrine\\Common\\Cache\\WinCacheCache', + 'doctrine_cache.xcache.class' => 'Doctrine\\Common\\Cache\\XcacheCache', + 'doctrine_cache.zenddata.class' => 'Doctrine\\Common\\Cache\\ZendDataCache', + 'doctrine_cache.security.acl.cache.class' => 'Doctrine\\Bundle\\DoctrineCacheBundle\\Acl\\Model\\AclCache', + 'doctrine.dbal.logger.chain.class' => 'Doctrine\\DBAL\\Logging\\LoggerChain', + 'doctrine.dbal.logger.profiling.class' => 'Doctrine\\DBAL\\Logging\\DebugStack', + 'doctrine.dbal.logger.class' => 'Symfony\\Bridge\\Doctrine\\Logger\\DbalLogger', + 'doctrine.dbal.configuration.class' => 'Doctrine\\DBAL\\Configuration', + 'doctrine.data_collector.class' => 'Doctrine\\Bundle\\DoctrineBundle\\DataCollector\\DoctrineDataCollector', + 'doctrine.dbal.connection.event_manager.class' => 'Symfony\\Bridge\\Doctrine\\ContainerAwareEventManager', + 'doctrine.dbal.connection_factory.class' => 'Doctrine\\Bundle\\DoctrineBundle\\ConnectionFactory', + 'doctrine.dbal.events.mysql_session_init.class' => 'Doctrine\\DBAL\\Event\\Listeners\\MysqlSessionInit', + 'doctrine.dbal.events.oracle_session_init.class' => 'Doctrine\\DBAL\\Event\\Listeners\\OracleSessionInit', + 'doctrine.class' => 'Doctrine\\Bundle\\DoctrineBundle\\Registry', + 'doctrine.entity_managers' => [ + 'default' => 'doctrine.orm.default_entity_manager', + ], + 'doctrine.default_entity_manager' => 'default', + 'doctrine.dbal.connection_factory.types' => [ + ], + 'doctrine.connections' => [ + 'default' => 'doctrine.dbal.default_connection', + ], + 'doctrine.default_connection' => 'default', + 'doctrine.orm.configuration.class' => 'Doctrine\\ORM\\Configuration', + 'doctrine.orm.entity_manager.class' => 'Doctrine\\ORM\\EntityManager', + 'doctrine.orm.manager_configurator.class' => 'Doctrine\\Bundle\\DoctrineBundle\\ManagerConfigurator', + 'doctrine.orm.cache.array.class' => 'Doctrine\\Common\\Cache\\ArrayCache', + 'doctrine.orm.cache.apc.class' => 'Doctrine\\Common\\Cache\\ApcCache', + 'doctrine.orm.cache.memcache.class' => 'Doctrine\\Common\\Cache\\MemcacheCache', + 'doctrine.orm.cache.memcache_host' => 'localhost', + 'doctrine.orm.cache.memcache_port' => 11211, + 'doctrine.orm.cache.memcache_instance.class' => 'Memcache', + 'doctrine.orm.cache.memcached.class' => 'Doctrine\\Common\\Cache\\MemcachedCache', + 'doctrine.orm.cache.memcached_host' => 'localhost', + 'doctrine.orm.cache.memcached_port' => 11211, + 'doctrine.orm.cache.memcached_instance.class' => 'Memcached', + 'doctrine.orm.cache.redis.class' => 'Doctrine\\Common\\Cache\\RedisCache', + 'doctrine.orm.cache.redis_host' => 'localhost', + 'doctrine.orm.cache.redis_port' => 6379, + 'doctrine.orm.cache.redis_instance.class' => 'Redis', + 'doctrine.orm.cache.xcache.class' => 'Doctrine\\Common\\Cache\\XcacheCache', + 'doctrine.orm.cache.wincache.class' => 'Doctrine\\Common\\Cache\\WinCacheCache', + 'doctrine.orm.cache.zenddata.class' => 'Doctrine\\Common\\Cache\\ZendDataCache', + 'doctrine.orm.metadata.driver_chain.class' => 'Doctrine\\Common\\Persistence\\Mapping\\Driver\\MappingDriverChain', + 'doctrine.orm.metadata.annotation.class' => 'Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver', + 'doctrine.orm.metadata.xml.class' => 'Doctrine\\ORM\\Mapping\\Driver\\SimplifiedXmlDriver', + 'doctrine.orm.metadata.yml.class' => 'Doctrine\\ORM\\Mapping\\Driver\\SimplifiedYamlDriver', + 'doctrine.orm.metadata.php.class' => 'Doctrine\\ORM\\Mapping\\Driver\\PHPDriver', + 'doctrine.orm.metadata.staticphp.class' => 'Doctrine\\ORM\\Mapping\\Driver\\StaticPHPDriver', + 'doctrine.orm.proxy_cache_warmer.class' => 'Symfony\\Bridge\\Doctrine\\CacheWarmer\\ProxyCacheWarmer', + 'form.type_guesser.doctrine.class' => 'Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmTypeGuesser', + 'doctrine.orm.validator.unique.class' => 'Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\UniqueEntityValidator', + 'doctrine.orm.validator_initializer.class' => 'Symfony\\Bridge\\Doctrine\\Validator\\DoctrineInitializer', + 'doctrine.orm.security.user.provider.class' => 'Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider', + 'doctrine.orm.listeners.resolve_target_entity.class' => 'Doctrine\\ORM\\Tools\\ResolveTargetEntityListener', + 'doctrine.orm.listeners.attach_entity_listeners.class' => 'Doctrine\\ORM\\Tools\\AttachEntityListenersListener', + 'doctrine.orm.naming_strategy.default.class' => 'Doctrine\\ORM\\Mapping\\DefaultNamingStrategy', + 'doctrine.orm.naming_strategy.underscore.class' => 'Doctrine\\ORM\\Mapping\\UnderscoreNamingStrategy', + 'doctrine.orm.quote_strategy.default.class' => 'Doctrine\\ORM\\Mapping\\DefaultQuoteStrategy', + 'doctrine.orm.quote_strategy.ansi.class' => 'Doctrine\\ORM\\Mapping\\AnsiQuoteStrategy', + 'doctrine.orm.entity_listener_resolver.class' => 'Doctrine\\ORM\\Mapping\\DefaultEntityListenerResolver', + 'doctrine.orm.second_level_cache.default_cache_factory.class' => 'Doctrine\\ORM\\Cache\\DefaultCacheFactory', + 'doctrine.orm.second_level_cache.default_region.class' => 'Doctrine\\ORM\\Cache\\Region\\DefaultRegion', + 'doctrine.orm.second_level_cache.filelock_region.class' => 'Doctrine\\ORM\\Cache\\Region\\FileLockRegion', + 'doctrine.orm.second_level_cache.logger_chain.class' => 'Doctrine\\ORM\\Cache\\Logging\\CacheLoggerChain', + 'doctrine.orm.second_level_cache.logger_statistics.class' => 'Doctrine\\ORM\\Cache\\Logging\\StatisticsCacheLogger', + 'doctrine.orm.second_level_cache.cache_configuration.class' => 'Doctrine\\ORM\\Cache\\CacheConfiguration', + 'doctrine.orm.second_level_cache.regions_configuration.class' => 'Doctrine\\ORM\\Cache\\RegionsConfiguration', + 'doctrine.orm.auto_generate_proxy_classes' => true, + 'doctrine.orm.proxy_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/doctrine/orm/Proxies', + 'doctrine.orm.proxy_namespace' => 'Proxies', + 'sensio_framework_extra.view.guesser.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Templating\\TemplateGuesser', + 'sensio_framework_extra.controller.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\ControllerListener', + 'sensio_framework_extra.routing.loader.annot_dir.class' => 'Symfony\\Component\\Routing\\Loader\\AnnotationDirectoryLoader', + 'sensio_framework_extra.routing.loader.annot_file.class' => 'Symfony\\Component\\Routing\\Loader\\AnnotationFileLoader', + 'sensio_framework_extra.routing.loader.annot_class.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Routing\\AnnotatedRouteControllerLoader', + 'sensio_framework_extra.converter.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\ParamConverterListener', + 'sensio_framework_extra.converter.manager.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\ParamConverterManager', + 'sensio_framework_extra.converter.doctrine.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\DoctrineParamConverter', + 'sensio_framework_extra.converter.datetime.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\DateTimeParamConverter', + 'sensio_framework_extra.view.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\TemplateListener', + 'chill_main.installation_name' => 'Chill', + 'chill_main.available_languages' => [ + 0 => 'fr', + ], + 'chill_main.routing.resources' => [ + 0 => '@ChillPersonBundle/Resources/config/routing.yml', + 1 => '@ChillCustomFieldsBundle/Resources/config/routing.yml', + 2 => '@ChillMainBundle/Resources/config/routing.yml', + ], + 'chill_custom_fields.customizables_entities' => [ + 0 => [ + 'class' => 'Chill\\PersonBundle\\Entity\\Person', + 'name' => 'PersonEntity', + 'options' => [ + ], + ], + ], + 'cl_chill_person.search.use_double_metaphone' => false, + 'web_profiler.controller.profiler.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\ProfilerController', + 'web_profiler.controller.router.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\RouterController', + 'web_profiler.controller.exception.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\ExceptionController', + 'twig.extension.webprofiler.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension', + 'web_profiler.debug_toolbar.position' => 'bottom', + 'sensio_distribution.webconfigurator.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Configurator', + 'sensio_distribution.webconfigurator.doctrine_step.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Step\\DoctrineStep', + 'sensio_distribution.webconfigurator.secret_step.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Step\\SecretStep', + 'sensio_distribution.security_checker.class' => 'SensioLabs\\Security\\SecurityChecker', + 'sensio_distribution.security_checker.command.class' => 'SensioLabs\\Security\\Command\\SecurityCheckerCommand', + 'data_collector.templates' => [ + 'data_collector.config' => [ + 0 => 'config', + 1 => '@WebProfiler/Collector/config.html.twig', + ], + 'data_collector.request' => [ + 0 => 'request', + 1 => '@WebProfiler/Collector/request.html.twig', + ], + 'data_collector.ajax' => [ + 0 => 'ajax', + 1 => '@WebProfiler/Collector/ajax.html.twig', + ], + 'data_collector.exception' => [ + 0 => 'exception', + 1 => '@WebProfiler/Collector/exception.html.twig', + ], + 'data_collector.events' => [ + 0 => 'events', + 1 => '@WebProfiler/Collector/events.html.twig', + ], + 'data_collector.logger' => [ + 0 => 'logger', + 1 => '@WebProfiler/Collector/logger.html.twig', + ], + 'data_collector.time' => [ + 0 => 'time', + 1 => '@WebProfiler/Collector/time.html.twig', + ], + 'data_collector.memory' => [ + 0 => 'memory', + 1 => '@WebProfiler/Collector/memory.html.twig', + ], + 'data_collector.router' => [ + 0 => 'router', + 1 => '@WebProfiler/Collector/router.html.twig', + ], + 'data_collector.form' => [ + 0 => 'form', + 1 => '@WebProfiler/Collector/form.html.twig', + ], + 'data_collector.translation' => [ + 0 => 'translation', + 1 => '@WebProfiler/Collector/translation.html.twig', + ], + 'data_collector.twig' => [ + 0 => 'twig', + 1 => '@WebProfiler/Collector/twig.html.twig', + ], + 'data_collector.security' => [ + 0 => 'security', + 1 => '@Security/Collector/security.html.twig', + ], + 'swiftmailer.data_collector' => [ + 0 => 'swiftmailer', + 1 => '@Swiftmailer/Collector/swiftmailer.html.twig', + ], + 'data_collector.doctrine' => [ + 0 => 'db', + 1 => '@Doctrine/Collector/db.html.twig', + ], + 'data_collector.dump' => [ + 0 => 'dump', + 1 => '@Debug/Profiler/dump.html.twig', + ], + ], + 'console.command.ids' => [ + 0 => 'sensio_distribution.security_checker.command', + ], + ]; } /** @@ -1066,7 +1769,7 @@ class appDevDebugProjectContainer extends Container */ protected function getDoctrine_Dbal_ConnectionFactoryService() { - return $this->services['doctrine.dbal.connection_factory'] = new \Doctrine\Bundle\DoctrineBundle\ConnectionFactory(array()); + return $this->services['doctrine.dbal.connection_factory'] = new \Doctrine\Bundle\DoctrineBundle\ConnectionFactory([]); } /** @@ -1087,9 +1790,26 @@ class appDevDebugProjectContainer extends Container $b->setSQLLogger($a); $c = new \Symfony\Bridge\Doctrine\ContainerAwareEventManager($this); - $c->addEventListener(array(0 => 'loadClassMetadata'), $this->get('doctrine.orm.default_listeners.attach_entity_listeners')); + $c->addEventListener([0 => 'loadClassMetadata'], $this->get('doctrine.orm.default_listeners.attach_entity_listeners')); - return $this->services['doctrine.dbal.default_connection'] = $this->get('doctrine.dbal.connection_factory')->createConnection(array('driver' => 'pdo_pgsql', 'host' => '127.0.0.1', 'port' => 5432, 'dbname' => 'chill_test', 'user' => 'chill', 'password' => 'chill', 'charset' => 'UTF8', 'driverOptions' => array()), $b, $c, array()); + return $this->services['doctrine.dbal.default_connection'] = $this->get('doctrine.dbal.connection_factory')->createConnection(['driver' => 'pdo_pgsql', 'host' => '127.0.0.1', 'port' => 5432, 'dbname' => 'chill_test', 'user' => 'chill', 'password' => 'chill', 'charset' => 'UTF8', 'driverOptions' => []], $b, $c, []); + } + + /** + * Gets the 'doctrine.dbal.logger.profiling.default' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Doctrine\DBAL\Logging\DebugStack A Doctrine\DBAL\Logging\DebugStack instance. + */ + protected function getDoctrine_Dbal_Logger_Profiling_DefaultService() + { + return $this->services['doctrine.dbal.logger.profiling.default'] = new \Doctrine\DBAL\Logging\DebugStack(); } /** @@ -1115,7 +1835,7 @@ class appDevDebugProjectContainer extends Container */ protected function getDoctrine_Orm_DefaultEntityManagerService() { - $a = new \Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver(array('/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/config/doctrine' => 'Chill\\MainBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/config/doctrine' => 'Chill\\CustomFieldsBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/config/doctrine' => 'Chill\\PersonBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Resources/config/doctrine' => 'Chill\\ActivityBundle\\Entity')); + $a = new \Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver(['/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/config/doctrine' => 'Chill\\MainBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/config/doctrine' => 'Chill\\CustomFieldsBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/config/doctrine' => 'Chill\\PersonBundle\\Entity', '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Resources/config/doctrine' => 'Chill\\ActivityBundle\\Entity']); $a->setGlobalBasename('mapping'); $b = new \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain(); @@ -1125,7 +1845,7 @@ class appDevDebugProjectContainer extends Container $b->addDriver($a, 'Chill\\ActivityBundle\\Entity'); $c = new \Doctrine\ORM\Configuration(); - $c->setEntityNamespaces(array('ChillMainBundle' => 'Chill\\MainBundle\\Entity', 'ChillCustomFieldsBundle' => 'Chill\\CustomFieldsBundle\\Entity', 'ChillPersonBundle' => 'Chill\\PersonBundle\\Entity', 'ChillActivityBundle' => 'Chill\\ActivityBundle\\Entity')); + $c->setEntityNamespaces(['ChillMainBundle' => 'Chill\\MainBundle\\Entity', 'ChillCustomFieldsBundle' => 'Chill\\CustomFieldsBundle\\Entity', 'ChillPersonBundle' => 'Chill\\PersonBundle\\Entity', 'ChillActivityBundle' => 'Chill\\ActivityBundle\\Entity']); $c->setMetadataCacheImpl($this->get('doctrine_cache.providers.doctrine.orm.default_metadata_cache')); $c->setQueryCacheImpl($this->get('doctrine_cache.providers.doctrine.orm.default_query_cache')); $c->setResultCacheImpl($this->get('doctrine_cache.providers.doctrine.orm.default_result_cache')); @@ -1170,7 +1890,7 @@ class appDevDebugProjectContainer extends Container */ protected function getDoctrine_Orm_DefaultManagerConfiguratorService() { - return $this->services['doctrine.orm.default_manager_configurator'] = new \Doctrine\Bundle\DoctrineBundle\ManagerConfigurator(array(), array()); + return $this->services['doctrine.orm.default_manager_configurator'] = new \Doctrine\Bundle\DoctrineBundle\ManagerConfigurator([], []); } /** @@ -1250,6 +1970,19 @@ class appDevDebugProjectContainer extends Container return $instance; } + /** + * Gets the 'doctrine' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Doctrine\Bundle\DoctrineBundle\Registry A Doctrine\Bundle\DoctrineBundle\Registry instance. + */ + protected function getDoctrineService() + { + return $this->services['doctrine'] = new \Doctrine\Bundle\DoctrineBundle\Registry($this, ['default' => 'doctrine.dbal.default_connection'], ['default' => 'doctrine.orm.default_entity_manager'], 'default', 'default'); + } + /** * Gets the 'file_locator' service. * @@ -1312,7 +2045,7 @@ class appDevDebugProjectContainer extends Container */ protected function getForm_RegistryService() { - return $this->services['form.registry'] = new \Symfony\Component\Form\FormRegistry(array(0 => new \Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension($this, array('form' => 'form.type.form', 'birthday' => 'form.type.birthday', 'checkbox' => 'form.type.checkbox', 'choice' => 'form.type.choice', 'collection' => 'form.type.collection', 'country' => 'form.type.country', 'date' => 'form.type.date', 'datetime' => 'form.type.datetime', 'email' => 'form.type.email', 'file' => 'form.type.file', 'hidden' => 'form.type.hidden', 'integer' => 'form.type.integer', 'language' => 'form.type.language', 'locale' => 'form.type.locale', 'money' => 'form.type.money', 'number' => 'form.type.number', 'password' => 'form.type.password', 'percent' => 'form.type.percent', 'radio' => 'form.type.radio', 'repeated' => 'form.type.repeated', 'search' => 'form.type.search', 'textarea' => 'form.type.textarea', 'text' => 'form.type.text', 'time' => 'form.type.time', 'timezone' => 'form.type.timezone', 'url' => 'form.type.url', 'button' => 'form.type.button', 'submit' => 'form.type.submit', 'reset' => 'form.type.reset', 'currency' => 'form.type.currency', 'entity' => 'form.type.entity', 'translatable_string' => 'chill.main.form.type.translatable.string', 'select2_choice' => 'chill.main.form.type.select2choice', 'select2_entity' => 'chill.main.form.type.select2entity', 'select2_chill_country' => 'chill.main.form.type.select2country', 'select2_chill_language' => 'chill.main.form.type.select2language', 'center' => 'chill.main.form.type.center', 'custom_field_choice' => 'chill.custom_field.custom_field_choice_type', 'custom_fields_group' => 'chill.custom_field.custom_fields_group_type', 'custom_field' => 'chill.custom_field.custom_field_type', 'custom_fields_group_linked_custom_fields' => 'chill.custom_field.custom_fields_group_linked_custom_fields', 'custom_field_title' => 'chill.custom_field.custom_fields_title_type', 'closing_motive' => 'chill.person.accompanying_period_closing_motive'), array('form' => array(0 => 'form.type_extension.form.http_foundation', 1 => 'form.type_extension.form.validator', 2 => 'form.type_extension.csrf', 3 => 'form.type_extension.form.data_collector'), 'repeated' => array(0 => 'form.type_extension.repeated.validator'), 'submit' => array(0 => 'form.type_extension.submit.validator')), array(0 => 'form.type_guesser.validator', 1 => 'form.type_guesser.doctrine'))), $this->get('form.resolved_type_factory')); + return $this->services['form.registry'] = new \Symfony\Component\Form\FormRegistry([0 => new \Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension($this, ['form' => 'form.type.form', 'birthday' => 'form.type.birthday', 'checkbox' => 'form.type.checkbox', 'choice' => 'form.type.choice', 'collection' => 'form.type.collection', 'country' => 'form.type.country', 'date' => 'form.type.date', 'datetime' => 'form.type.datetime', 'email' => 'form.type.email', 'file' => 'form.type.file', 'hidden' => 'form.type.hidden', 'integer' => 'form.type.integer', 'language' => 'form.type.language', 'locale' => 'form.type.locale', 'money' => 'form.type.money', 'number' => 'form.type.number', 'password' => 'form.type.password', 'percent' => 'form.type.percent', 'radio' => 'form.type.radio', 'repeated' => 'form.type.repeated', 'search' => 'form.type.search', 'textarea' => 'form.type.textarea', 'text' => 'form.type.text', 'time' => 'form.type.time', 'timezone' => 'form.type.timezone', 'url' => 'form.type.url', 'button' => 'form.type.button', 'submit' => 'form.type.submit', 'reset' => 'form.type.reset', 'currency' => 'form.type.currency', 'entity' => 'form.type.entity', 'translatable_string' => 'chill.main.form.type.translatable.string', 'select2_choice' => 'chill.main.form.type.select2choice', 'select2_entity' => 'chill.main.form.type.select2entity', 'select2_chill_country' => 'chill.main.form.type.select2country', 'select2_chill_language' => 'chill.main.form.type.select2language', 'center' => 'chill.main.form.type.center', 'custom_field_choice' => 'chill.custom_field.custom_field_choice_type', 'custom_fields_group' => 'chill.custom_field.custom_fields_group_type', 'custom_field' => 'chill.custom_field.custom_field_type', 'custom_fields_group_linked_custom_fields' => 'chill.custom_field.custom_fields_group_linked_custom_fields', 'custom_field_title' => 'chill.custom_field.custom_fields_title_type', 'closing_motive' => 'chill.person.accompanying_period_closing_motive'], ['form' => [0 => 'form.type_extension.form.http_foundation', 1 => 'form.type_extension.form.validator', 2 => 'form.type_extension.csrf', 3 => 'form.type_extension.form.data_collector'], 'repeated' => [0 => 'form.type_extension.repeated.validator'], 'submit' => [0 => 'form.type_extension.submit.validator']], [0 => 'form.type_guesser.validator', 1 => 'form.type_guesser.doctrine'])], $this->get('form.resolved_type_factory')); } /** @@ -1666,19 +2399,6 @@ class appDevDebugProjectContainer extends Container return $this->services['form.type.submit'] = new \Symfony\Component\Form\Extension\Core\Type\SubmitType(); } - /** - * Gets the 'form.type.text' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Form\Extension\Core\Type\TextType A Symfony\Component\Form\Extension\Core\Type\TextType instance. - */ - protected function getForm_Type_TextService() - { - return $this->services['form.type.text'] = new \Symfony\Component\Form\Extension\Core\Type\TextType(); - } - /** * Gets the 'form.type.textarea' service. * @@ -1692,6 +2412,19 @@ class appDevDebugProjectContainer extends Container return $this->services['form.type.textarea'] = new \Symfony\Component\Form\Extension\Core\Type\TextareaType(); } + /** + * Gets the 'form.type.text' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\Form\Extension\Core\Type\TextType A Symfony\Component\Form\Extension\Core\Type\TextType instance. + */ + protected function getForm_Type_TextService() + { + return $this->services['form.type.text'] = new \Symfony\Component\Form\Extension\Core\Type\TextType(); + } + /** * Gets the 'form.type.time' service. * @@ -1866,7 +2599,7 @@ class appDevDebugProjectContainer extends Container */ protected function getFragment_Renderer_EsiService() { - $this->services['fragment.renderer.esi'] = $instance = new \Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer(NULL, $this->get('fragment.renderer.inline'), $this->get('uri_signer')); + $this->services['fragment.renderer.esi'] = $instance = new \Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer(null, $this->get('fragment.renderer.inline'), $this->get('uri_signer')); $instance->setFragmentPath('/_fragment'); @@ -1883,7 +2616,7 @@ class appDevDebugProjectContainer extends Container */ protected function getFragment_Renderer_HincludeService() { - $this->services['fragment.renderer.hinclude'] = $instance = new \Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer($this->get('twig'), $this->get('uri_signer'), NULL); + $this->services['fragment.renderer.hinclude'] = $instance = new \Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer($this->get('twig'), $this->get('uri_signer'), null); $instance->setFragmentPath('/_fragment'); @@ -1917,7 +2650,7 @@ class appDevDebugProjectContainer extends Container */ protected function getFragment_Renderer_SsiService() { - $this->services['fragment.renderer.ssi'] = $instance = new \Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer(NULL, $this->get('fragment.renderer.inline'), $this->get('uri_signer')); + $this->services['fragment.renderer.ssi'] = $instance = new \Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer(null, $this->get('fragment.renderer.inline'), $this->get('uri_signer')); $instance->setFragmentPath('/_fragment'); @@ -2163,6 +2896,19 @@ class appDevDebugProjectContainer extends Container return $instance; } + /** + * Gets the 'profiler_listener' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\HttpKernel\EventListener\ProfilerListener A Symfony\Component\HttpKernel\EventListener\ProfilerListener instance. + */ + protected function getProfilerListenerService() + { + return $this->services['profiler_listener'] = new \Symfony\Component\HttpKernel\EventListener\ProfilerListener($this->get('profiler'), null, false, false, $this->get('request_stack')); + } + /** * Gets the 'profiler' service. * @@ -2177,6 +2923,7 @@ class appDevDebugProjectContainer extends Container $b = $this->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE); $c = new \Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector(); + if ($this->has('kernel')) { $c->setKernel($b); } @@ -2206,19 +2953,6 @@ class appDevDebugProjectContainer extends Container return $instance; } - /** - * Gets the 'profiler_listener' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\HttpKernel\EventListener\ProfilerListener A Symfony\Component\HttpKernel\EventListener\ProfilerListener instance. - */ - protected function getProfilerListenerService() - { - return $this->services['profiler_listener'] = new \Symfony\Component\HttpKernel\EventListener\ProfilerListener($this->get('profiler'), NULL, false, false, $this->get('request_stack')); - } - /** * Gets the 'property_accessor' service. * @@ -2277,16 +3011,20 @@ class appDevDebugProjectContainer extends Container } /** - * Gets the 'router' service. + * Gets the 'router.request_context' service. * * This service is shared. * This method always returns the same instance of the service. * - * @return \Symfony\Bundle\FrameworkBundle\Routing\Router A Symfony\Bundle\FrameworkBundle\Routing\Router instance. + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Routing\RequestContext A Symfony\Component\Routing\RequestContext instance. */ - protected function getRouterService() + protected function getRouter_RequestContextService() { - return $this->services['router'] = new \Symfony\Bundle\FrameworkBundle\Routing\Router($this, '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/config/routing.yml', array('cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev', 'debug' => true, 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', 'generator_cache_class' => 'appDevUrlGenerator', 'matcher_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_base_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', 'matcher_cache_class' => 'appDevUrlMatcher', 'strict_requirements' => true), $this->get('router.request_context', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('monolog.logger.router', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + return $this->services['router.request_context'] = new \Symfony\Component\Routing\RequestContext('', 'GET', 'localhost', 'http', 80, 443); } /** @@ -2302,6 +3040,19 @@ class appDevDebugProjectContainer extends Container return $this->services['router_listener'] = new \Symfony\Component\HttpKernel\EventListener\RouterListener($this->get('router'), $this->get('router.request_context', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('monolog.logger.request', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('request_stack')); } + /** + * Gets the 'router' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Bundle\FrameworkBundle\Routing\Router A Symfony\Bundle\FrameworkBundle\Routing\Router instance. + */ + protected function getRouterService() + { + return $this->services['router'] = new \Symfony\Bundle\FrameworkBundle\Routing\Router($this, '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/config/routing.yml', ['cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev', 'debug' => true, 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', 'generator_cache_class' => 'appDevUrlGenerator', 'matcher_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_base_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', 'matcher_cache_class' => 'appDevUrlMatcher', 'strict_requirements' => true], $this->get('router.request_context', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('monolog.logger.router', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + } + /** * Gets the 'routing.loader' service. * @@ -2329,6 +3080,64 @@ class appDevDebugProjectContainer extends Container return $this->services['routing.loader'] = new \Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader($this->get('controller_name_converter'), $this->get('monolog.logger.router', ContainerInterface::NULL_ON_INVALID_REFERENCE), $d); } + /** + * Gets the 'security.access.decision_manager' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\Authorization\AccessDecisionManager A Symfony\Component\Security\Core\Authorization\AccessDecisionManager instance. + */ + protected function getSecurity_Access_DecisionManagerService() + { + $a = $this->get('security.authentication.trust_resolver'); + $b = $this->get('security.role_hierarchy'); + + return $this->services['security.access.decision_manager'] = new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager([0 => $this->get('chill.person.security.authorization.person'), 1 => new \Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter(new \Symfony\Component\Security\Core\Authorization\ExpressionLanguage(), $a, $b), 2 => new \Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter($b), 3 => new \Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter($a)], 'affirmative', false, true); + } + + /** + * Gets the 'security.authentication.manager' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager A Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager instance. + */ + protected function getSecurity_Authentication_ManagerService() + { + $this->services['security.authentication.manager'] = $instance = new \Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager([0 => new \Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider($this->get('security.user.provider.concrete.chain_provider'), new \Symfony\Component\Security\Core\User\UserChecker(), 'default', $this->get('security.encoder_factory'), true), 1 => new \Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider('5593aedf3be85')], true); + + $instance->setEventDispatcher($this->get('debug.event_dispatcher')); + + return $instance; + } + + /** + * Gets the 'security.authentication.trust_resolver' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver A Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver instance. + */ + protected function getSecurity_Authentication_TrustResolverService() + { + return $this->services['security.authentication.trust_resolver'] = new \Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver('Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken', 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken'); + } + /** * Gets the 'security.authentication_utils' service. * @@ -2391,20 +3200,7 @@ class appDevDebugProjectContainer extends Container */ protected function getSecurity_EncoderFactoryService() { - return $this->services['security.encoder_factory'] = new \Symfony\Component\Security\Core\Encoder\EncoderFactory(array('Chill\\MainBundle\\Entity\\User' => array('class' => 'Symfony\\Component\\Security\\Core\\Encoder\\BCryptPasswordEncoder', 'arguments' => array(0 => 13)), 'Symfony\\Component\\Security\\Core\\User\\User' => array('class' => 'Symfony\\Component\\Security\\Core\\Encoder\\PlaintextPasswordEncoder', 'arguments' => array(0 => false)))); - } - - /** - * Gets the 'security.firewall' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Security\Http\Firewall A Symfony\Component\Security\Http\Firewall instance. - */ - protected function getSecurity_FirewallService() - { - return $this->services['security.firewall'] = new \Symfony\Component\Security\Http\Firewall(new \Symfony\Bundle\SecurityBundle\Security\FirewallMap($this, array('security.firewall.map.context.dev' => new \Symfony\Component\HttpFoundation\RequestMatcher('^/(_(profiler|wdt)|css|images|js)/'), 'security.firewall.map.context.default' => NULL)), $this->get('debug.event_dispatcher')); + return $this->services['security.encoder_factory'] = new \Symfony\Component\Security\Core\Encoder\EncoderFactory(['Chill\\MainBundle\\Entity\\User' => ['class' => 'Symfony\\Component\\Security\\Core\\Encoder\\BCryptPasswordEncoder', 'arguments' => [0 => 13]], 'Symfony\\Component\\Security\\Core\\User\\User' => ['class' => 'Symfony\\Component\\Security\\Core\\Encoder\\PlaintextPasswordEncoder', 'arguments' => [0 => false]]]); } /** @@ -2428,17 +3224,17 @@ class appDevDebugProjectContainer extends Container $h = new \Symfony\Component\Security\Http\HttpUtils($d, $d); - $i = new \Symfony\Component\Security\Http\Firewall\LogoutListener($b, $h, new \Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler($h, '/'), array('csrf_parameter' => '_csrf_token', 'intention' => 'logout', 'logout_path' => '/logout')); + $i = new \Symfony\Component\Security\Http\Firewall\LogoutListener($b, $h, new \Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler($h, '/'), ['csrf_parameter' => '_csrf_token', 'intention' => 'logout', 'logout_path' => '/logout']); $i->addHandler(new \Symfony\Component\Security\Http\Logout\SessionLogoutHandler()); - $j = new \Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler($h, array()); - $j->setOptions(array('always_use_default_target_path' => false, 'default_target_path' => '/', 'login_path' => '/login', 'target_path_parameter' => '_target_path', 'use_referer' => false)); + $j = new \Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler($h, []); + $j->setOptions(['always_use_default_target_path' => false, 'default_target_path' => '/', 'login_path' => '/login', 'target_path_parameter' => '_target_path', 'use_referer' => false]); $j->setProviderKey('default'); - $k = new \Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler($e, $h, array(), $a); - $k->setOptions(array('login_path' => '/login', 'failure_path' => NULL, 'failure_forward' => false, 'failure_path_parameter' => '_failure_path')); + $k = new \Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler($e, $h, [], $a); + $k->setOptions(['login_path' => '/login', 'failure_path' => null, 'failure_forward' => false, 'failure_path_parameter' => '_failure_path']); - return $this->services['security.firewall.map.context.default'] = new \Symfony\Bundle\SecurityBundle\Security\FirewallContext(array(0 => new \Symfony\Component\Security\Http\Firewall\ChannelListener($g, new \Symfony\Component\Security\Http\EntryPoint\RetryAuthenticationEntryPoint(80, 443), $a), 1 => new \Symfony\Component\Security\Http\Firewall\ContextListener($b, array(0 => $this->get('security.user.provider.concrete.chain_provider'), 1 => $this->get('security.user.provider.concrete.in_memory'), 2 => $this->get('security.user.provider.concrete.users')), 'default', $a, $c), 2 => $i, 3 => new \Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener($b, $f, new \Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy('migrate'), $h, 'default', $j, $k, array('csrf_parameter' => '_csrf_token', 'intention' => 'authenticate', 'check_path' => '/login_check', 'use_forward' => false, 'require_previous_session' => true, 'username_parameter' => '_username', 'password_parameter' => '_password', 'post_only' => true), $a, $c, $this->get('form.csrf_provider')), 4 => new \Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener($b, '5593aedf3be85', $a, $f), 5 => new \Symfony\Component\Security\Http\Firewall\AccessListener($b, $this->get('security.access.decision_manager'), $g, $f)), new \Symfony\Component\Security\Http\Firewall\ExceptionListener($b, $this->get('security.authentication.trust_resolver'), $h, 'default', new \Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint($e, $h, '/login', false), NULL, NULL, $a)); + return $this->services['security.firewall.map.context.default'] = new \Symfony\Bundle\SecurityBundle\Security\FirewallContext([0 => new \Symfony\Component\Security\Http\Firewall\ChannelListener($g, new \Symfony\Component\Security\Http\EntryPoint\RetryAuthenticationEntryPoint(80, 443), $a), 1 => new \Symfony\Component\Security\Http\Firewall\ContextListener($b, [0 => $this->get('security.user.provider.concrete.chain_provider'), 1 => $this->get('security.user.provider.concrete.in_memory'), 2 => $this->get('security.user.provider.concrete.users')], 'default', $a, $c), 2 => $i, 3 => new \Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener($b, $f, new \Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy('migrate'), $h, 'default', $j, $k, ['csrf_parameter' => '_csrf_token', 'intention' => 'authenticate', 'check_path' => '/login_check', 'use_forward' => false, 'require_previous_session' => true, 'username_parameter' => '_username', 'password_parameter' => '_password', 'post_only' => true], $a, $c, $this->get('form.csrf_provider')), 4 => new \Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener($b, '5593aedf3be85', $a, $f), 5 => new \Symfony\Component\Security\Http\Firewall\AccessListener($b, $this->get('security.access.decision_manager'), $g, $f)], new \Symfony\Component\Security\Http\Firewall\ExceptionListener($b, $this->get('security.authentication.trust_resolver'), $h, 'default', new \Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint($e, $h, '/login', false), null, null, $a)); } /** @@ -2451,7 +3247,41 @@ class appDevDebugProjectContainer extends Container */ protected function getSecurity_Firewall_Map_Context_DevService() { - return $this->services['security.firewall.map.context.dev'] = new \Symfony\Bundle\SecurityBundle\Security\FirewallContext(array(), NULL); + return $this->services['security.firewall.map.context.dev'] = new \Symfony\Bundle\SecurityBundle\Security\FirewallContext([], null); + } + + /** + * Gets the 'security.firewall' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\Security\Http\Firewall A Symfony\Component\Security\Http\Firewall instance. + */ + protected function getSecurity_FirewallService() + { + return $this->services['security.firewall'] = new \Symfony\Component\Security\Http\Firewall(new \Symfony\Bundle\SecurityBundle\Security\FirewallMap($this, ['security.firewall.map.context.dev' => new \Symfony\Component\HttpFoundation\RequestMatcher('^/(_(profiler|wdt)|css|images|js)/'), 'security.firewall.map.context.default' => null]), $this->get('debug.event_dispatcher')); + } + + /** + * Gets the 'security.logout_url_generator' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Http\Logout\LogoutUrlGenerator A Symfony\Component\Security\Http\Logout\LogoutUrlGenerator instance. + */ + protected function getSecurity_LogoutUrlGeneratorService() + { + $this->services['security.logout_url_generator'] = $instance = new \Symfony\Component\Security\Http\Logout\LogoutUrlGenerator($this->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('router', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + + $instance->registerListener('default', '/logout', 'logout', '_csrf_token', null); + + return $instance; } /** @@ -2480,6 +3310,23 @@ class appDevDebugProjectContainer extends Container return $this->services['security.rememberme.response_listener'] = new \Symfony\Component\Security\Http\RememberMe\ResponseListener(); } + /** + * Gets the 'security.role_hierarchy' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\Role\RoleHierarchy A Symfony\Component\Security\Core\Role\RoleHierarchy instance. + */ + protected function getSecurity_RoleHierarchyService() + { + return $this->services['security.role_hierarchy'] = new \Symfony\Component\Security\Core\Role\RoleHierarchy(['CHILL_PERSON_UPDATE' => [0 => 'CHILL_PERSON_SEE'], 'CHILL_PERSON_CREATE' => [0 => 'CHILL_PERSON_SEE']]); + } + /** * Gets the 'security.secure_random' service. * @@ -2506,6 +3353,61 @@ class appDevDebugProjectContainer extends Container return $this->services['security.token_storage'] = new \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage(); } + /** + * Gets the 'security.user.provider.concrete.chain_provider' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\User\ChainUserProvider A Symfony\Component\Security\Core\User\ChainUserProvider instance. + */ + protected function getSecurity_User_Provider_Concrete_ChainProviderService() + { + return $this->services['security.user.provider.concrete.chain_provider'] = new \Symfony\Component\Security\Core\User\ChainUserProvider([0 => $this->get('security.user.provider.concrete.in_memory'), 1 => $this->get('security.user.provider.concrete.users')]); + } + + /** + * Gets the 'security.user.provider.concrete.in_memory' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\Security\Core\User\InMemoryUserProvider A Symfony\Component\Security\Core\User\InMemoryUserProvider instance. + */ + protected function getSecurity_User_Provider_Concrete_InMemoryService() + { + $this->services['security.user.provider.concrete.in_memory'] = $instance = new \Symfony\Component\Security\Core\User\InMemoryUserProvider(); + + $instance->createUser(new \Symfony\Component\Security\Core\User\User('admin', 'olala', [0 => 'ROLE_ADMIN'])); + + return $instance; + } + + /** + * Gets the 'security.user.provider.concrete.users' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Bridge\Doctrine\Security\User\EntityUserProvider A Symfony\Bridge\Doctrine\Security\User\EntityUserProvider instance. + */ + protected function getSecurity_User_Provider_Concrete_UsersService() + { + return $this->services['security.user.provider.concrete.users'] = new \Symfony\Bridge\Doctrine\Security\User\EntityUserProvider($this->get('doctrine'), 'Chill\\MainBundle\\Entity\\User', 'username', null); + } + /** * Gets the 'security.validator.user_password' service. * @@ -2519,19 +3421,6 @@ class appDevDebugProjectContainer extends Container return $this->services['security.validator.user_password'] = new \Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator($this->get('security.token_storage'), $this->get('security.encoder_factory')); } - /** - * Gets the 'sensio_distribution.security_checker' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \SensioLabs\Security\SecurityChecker A SensioLabs\Security\SecurityChecker instance. - */ - protected function getSensioDistribution_SecurityCheckerService() - { - return $this->services['sensio_distribution.security_checker'] = new \SensioLabs\Security\SecurityChecker(); - } - /** * Gets the 'sensio_distribution.security_checker.command' service. * @@ -2545,6 +3434,19 @@ class appDevDebugProjectContainer extends Container return $this->services['sensio_distribution.security_checker.command'] = new \SensioLabs\Security\Command\SecurityCheckerCommand($this->get('sensio_distribution.security_checker')); } + /** + * Gets the 'sensio_distribution.security_checker' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \SensioLabs\Security\SecurityChecker A SensioLabs\Security\SecurityChecker instance. + */ + protected function getSensioDistribution_SecurityCheckerService() + { + return $this->services['sensio_distribution.security_checker'] = new \SensioLabs\Security\SecurityChecker(); + } + /** * Gets the 'sensio_distribution.webconfigurator' service. * @@ -2656,7 +3558,7 @@ class appDevDebugProjectContainer extends Container */ protected function getSensioFrameworkExtra_Security_ListenerService() { - return $this->services['sensio_framework_extra.security.listener'] = new \Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener(NULL, new \Sensio\Bundle\FrameworkExtraBundle\Security\ExpressionLanguage(), $this->get('security.authentication.trust_resolver', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.role_hierarchy', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.authorization_checker', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + return $this->services['sensio_framework_extra.security.listener'] = new \Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener(null, new \Sensio\Bundle\FrameworkExtraBundle\Security\ExpressionLanguage(), $this->get('security.authentication.trust_resolver', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.role_hierarchy', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.authorization_checker', ContainerInterface::NULL_ON_INVALID_REFERENCE)); } /** @@ -2698,19 +3600,6 @@ class appDevDebugProjectContainer extends Container throw new RuntimeException('You have requested a synthetic service ("service_container"). The DIC does not know how to construct this service.'); } - /** - * Gets the 'session' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\HttpFoundation\Session\Session A Symfony\Component\HttpFoundation\Session\Session instance. - */ - protected function getSessionService() - { - return $this->services['session'] = new \Symfony\Component\HttpFoundation\Session\Session($this->get('session.storage.filesystem'), new \Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag(), new \Symfony\Component\HttpFoundation\Session\Flash\FlashBag()); - } - /** * Gets the 'session.handler' service. * @@ -2750,6 +3639,23 @@ class appDevDebugProjectContainer extends Container return $this->services['session.storage.filesystem'] = new \Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage('/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/sessions', 'MOCKSESSID', $this->get('session.storage.metadata_bag')); } + /** + * Gets the 'session.storage.metadata_bag' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag A Symfony\Component\HttpFoundation\Session\Storage\MetadataBag instance. + */ + protected function getSession_Storage_MetadataBagService() + { + return $this->services['session.storage.metadata_bag'] = new \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag('_sf2_meta', '0'); + } + /** * Gets the 'session.storage.native' service. * @@ -2760,7 +3666,7 @@ class appDevDebugProjectContainer extends Container */ protected function getSession_Storage_NativeService() { - return $this->services['session.storage.native'] = new \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage(array('gc_probability' => 1), $this->get('session.handler'), $this->get('session.storage.metadata_bag')); + return $this->services['session.storage.native'] = new \Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage(['gc_probability' => 1], $this->get('session.handler'), $this->get('session.storage.metadata_bag')); } /** @@ -2789,6 +3695,19 @@ class appDevDebugProjectContainer extends Container return $this->services['session_listener'] = new \Symfony\Bundle\FrameworkBundle\EventListener\SessionListener($this); } + /** + * Gets the 'session' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\HttpFoundation\Session\Session A Symfony\Component\HttpFoundation\Session\Session instance. + */ + protected function getSessionService() + { + return $this->services['session'] = new \Symfony\Component\HttpFoundation\Session\Session($this->get('session.storage.filesystem'), new \Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag(), new \Symfony\Component\HttpFoundation\Session\Flash\FlashBag()); + } + /** * Gets the 'streamed_response_listener' service. * @@ -2815,19 +3734,6 @@ class appDevDebugProjectContainer extends Container return $this->services['swiftmailer.email_sender.listener'] = new \Symfony\Bundle\SwiftmailerBundle\EventListener\EmailSenderListener($this, $this->get('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE)); } - /** - * Gets the 'swiftmailer.mailer.default' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Swift_Mailer A Swift_Mailer instance. - */ - protected function getSwiftmailer_Mailer_DefaultService() - { - return $this->services['swiftmailer.mailer.default'] = new \Swift_Mailer($this->get('swiftmailer.mailer.default.transport')); - } - /** * Gets the 'swiftmailer.mailer.default.plugin.messagelogger' service. * @@ -2851,34 +3757,34 @@ class appDevDebugProjectContainer extends Container */ protected function getSwiftmailer_Mailer_Default_TransportService() { - $a = new \Swift_Transport_Esmtp_AuthHandler(array(0 => new \Swift_Transport_Esmtp_Auth_CramMd5Authenticator(), 1 => new \Swift_Transport_Esmtp_Auth_LoginAuthenticator(), 2 => new \Swift_Transport_Esmtp_Auth_PlainAuthenticator())); - $a->setUsername(NULL); - $a->setPassword(NULL); - $a->setAuthMode(NULL); + $a = new \Swift_Transport_Esmtp_AuthHandler([0 => new \Swift_Transport_Esmtp_Auth_CramMd5Authenticator(), 1 => new \Swift_Transport_Esmtp_Auth_LoginAuthenticator(), 2 => new \Swift_Transport_Esmtp_Auth_PlainAuthenticator()]); + $a->setUsername(null); + $a->setPassword(null); + $a->setAuthMode(null); - $this->services['swiftmailer.mailer.default.transport'] = $instance = new \Swift_Transport_EsmtpTransport(new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()), array(0 => $a), new \Swift_Events_SimpleEventDispatcher()); + $this->services['swiftmailer.mailer.default.transport'] = $instance = new \Swift_Transport_EsmtpTransport(new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()), [0 => $a], new \Swift_Events_SimpleEventDispatcher()); $instance->setHost('localhost'); $instance->setPort(25); - $instance->setEncryption(NULL); + $instance->setEncryption(null); $instance->setTimeout(30); - $instance->setSourceIp(NULL); + $instance->setSourceIp(null); $instance->registerPlugin($this->get('swiftmailer.mailer.default.plugin.messagelogger')); return $instance; } /** - * Gets the 'templating' service. + * Gets the 'swiftmailer.mailer.default' service. * * This service is shared. * This method always returns the same instance of the service. * - * @return \Symfony\Bundle\TwigBundle\TwigEngine A Symfony\Bundle\TwigBundle\TwigEngine instance. + * @return \Swift_Mailer A Swift_Mailer instance. */ - protected function getTemplatingService() + protected function getSwiftmailer_Mailer_DefaultService() { - return $this->services['templating'] = new \Symfony\Bundle\TwigBundle\TwigEngine($this->get('twig'), $this->get('templating.name_parser'), $this->get('templating.locator')); + return $this->services['swiftmailer.mailer.default'] = new \Swift_Mailer($this->get('swiftmailer.mailer.default.transport')); } /** @@ -2904,7 +3810,7 @@ class appDevDebugProjectContainer extends Container */ protected function getTemplating_Helper_AssetsService() { - return $this->services['templating.helper.assets'] = new \Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper($this->get('assets.packages'), array()); + return $this->services['templating.helper.assets'] = new \Symfony\Bundle\FrameworkBundle\Templating\Helper\AssetsHelper($this->get('assets.packages'), []); } /** @@ -2959,6 +3865,23 @@ class appDevDebugProjectContainer extends Container return $this->services['templating.loader'] = new \Symfony\Bundle\FrameworkBundle\Templating\Loader\FilesystemLoader($this->get('templating.locator')); } + /** + * Gets the 'templating.locator' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * This service is private. + * If you want to be able to request this service from the container directly, + * make it public, otherwise you might end up with broken code. + * + * @return \Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator A Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator instance. + */ + protected function getTemplating_LocatorService() + { + return $this->services['templating.locator'] = new \Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator($this->get('file_locator'), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev'); + } + /** * Gets the 'templating.name_parser' service. * @@ -2973,13 +3896,16 @@ class appDevDebugProjectContainer extends Container } /** - * Gets the 'test.client' service. + * Gets the 'templating' service. * - * @return \Symfony\Bundle\FrameworkBundle\Client A Symfony\Bundle\FrameworkBundle\Client instance. + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Bundle\TwigBundle\TwigEngine A Symfony\Bundle\TwigBundle\TwigEngine instance. */ - protected function getTest_ClientService() + protected function getTemplatingService() { - return new \Symfony\Bundle\FrameworkBundle\Client($this->get('kernel'), array(), new \Symfony\Component\BrowserKit\History(), new \Symfony\Component\BrowserKit\CookieJar()); + return $this->services['templating'] = new \Symfony\Bundle\TwigBundle\TwigEngine($this->get('twig'), $this->get('templating.name_parser'), $this->get('templating.locator')); } /** @@ -3002,6 +3928,16 @@ class appDevDebugProjectContainer extends Container return new \Symfony\Component\BrowserKit\History(); } + /** + * Gets the 'test.client' service. + * + * @return \Symfony\Bundle\FrameworkBundle\Client A Symfony\Bundle\FrameworkBundle\Client instance. + */ + protected function getTest_ClientService() + { + return new \Symfony\Bundle\FrameworkBundle\Client($this->get('kernel'), [], new \Symfony\Component\BrowserKit\History(), new \Symfony\Component\BrowserKit\CookieJar()); + } + /** * Gets the 'test.session.listener' service. * @@ -3145,24 +4081,6 @@ class appDevDebugProjectContainer extends Container return $this->services['translation.dumper.yml'] = new \Symfony\Component\Translation\Dumper\YamlFileDumper(); } - /** - * Gets the 'translation.extractor' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Translation\Extractor\ChainExtractor A Symfony\Component\Translation\Extractor\ChainExtractor instance. - */ - protected function getTranslation_ExtractorService() - { - $this->services['translation.extractor'] = $instance = new \Symfony\Component\Translation\Extractor\ChainExtractor(); - - $instance->addExtractor('php', $this->get('translation.extractor.php')); - $instance->addExtractor('twig', $this->get('twig.translation.extractor')); - - return $instance; - } - /** * Gets the 'translation.extractor.php' service. * @@ -3177,31 +4095,19 @@ class appDevDebugProjectContainer extends Container } /** - * Gets the 'translation.loader' service. + * Gets the 'translation.extractor' service. * * This service is shared. * This method always returns the same instance of the service. * - * @return \Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader A Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader instance. + * @return \Symfony\Component\Translation\Extractor\ChainExtractor A Symfony\Component\Translation\Extractor\ChainExtractor instance. */ - protected function getTranslation_LoaderService() + protected function getTranslation_ExtractorService() { - $a = $this->get('translation.loader.xliff'); + $this->services['translation.extractor'] = $instance = new \Symfony\Component\Translation\Extractor\ChainExtractor(); - $this->services['translation.loader'] = $instance = new \Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader(); - - $instance->addLoader('php', $this->get('translation.loader.php')); - $instance->addLoader('yml', $this->get('translation.loader.yml')); - $instance->addLoader('xlf', $a); - $instance->addLoader('xliff', $a); - $instance->addLoader('po', $this->get('translation.loader.po')); - $instance->addLoader('mo', $this->get('translation.loader.mo')); - $instance->addLoader('ts', $this->get('translation.loader.qt')); - $instance->addLoader('csv', $this->get('translation.loader.csv')); - $instance->addLoader('res', $this->get('translation.loader.res')); - $instance->addLoader('dat', $this->get('translation.loader.dat')); - $instance->addLoader('ini', $this->get('translation.loader.ini')); - $instance->addLoader('json', $this->get('translation.loader.json')); + $instance->addExtractor('php', $this->get('translation.extractor.php')); + $instance->addExtractor('twig', $this->get('twig.translation.extractor')); return $instance; } @@ -3349,6 +4255,36 @@ class appDevDebugProjectContainer extends Container return $this->services['translation.loader.yml'] = new \Symfony\Component\Translation\Loader\YamlFileLoader(); } + /** + * Gets the 'translation.loader' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader A Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader instance. + */ + protected function getTranslation_LoaderService() + { + $a = $this->get('translation.loader.xliff'); + + $this->services['translation.loader'] = $instance = new \Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader(); + + $instance->addLoader('php', $this->get('translation.loader.php')); + $instance->addLoader('yml', $this->get('translation.loader.yml')); + $instance->addLoader('xlf', $a); + $instance->addLoader('xliff', $a); + $instance->addLoader('po', $this->get('translation.loader.po')); + $instance->addLoader('mo', $this->get('translation.loader.mo')); + $instance->addLoader('ts', $this->get('translation.loader.qt')); + $instance->addLoader('csv', $this->get('translation.loader.csv')); + $instance->addLoader('res', $this->get('translation.loader.res')); + $instance->addLoader('dat', $this->get('translation.loader.dat')); + $instance->addLoader('ini', $this->get('translation.loader.ini')); + $instance->addLoader('json', $this->get('translation.loader.json')); + + return $instance; + } + /** * Gets the 'translation.writer' service. * @@ -3375,19 +4311,6 @@ class appDevDebugProjectContainer extends Container return $instance; } - /** - * Gets the 'translator' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Translation\DataCollectorTranslator A Symfony\Component\Translation\DataCollectorTranslator instance. - */ - protected function getTranslatorService() - { - return $this->services['translator'] = new \Symfony\Component\Translation\DataCollectorTranslator(new \Symfony\Component\Translation\LoggingTranslator($this->get('translator.default'), $this->get('monolog.logger.translation'))); - } - /** * Gets the 'translator.default' service. * @@ -3398,9 +4321,9 @@ class appDevDebugProjectContainer extends Container */ protected function getTranslator_DefaultService() { - $this->services['translator.default'] = $instance = new \Symfony\Bundle\FrameworkBundle\Translation\Translator($this, new \Symfony\Component\Translation\MessageSelector(), array('translation.loader.php' => array(0 => 'php'), 'translation.loader.yml' => array(0 => 'yml'), 'translation.loader.xliff' => array(0 => 'xlf', 1 => 'xliff'), 'translation.loader.po' => array(0 => 'po'), 'translation.loader.mo' => array(0 => 'mo'), 'translation.loader.qt' => array(0 => 'ts'), 'translation.loader.csv' => array(0 => 'csv'), 'translation.loader.res' => array(0 => 'res'), 'translation.loader.dat' => array(0 => 'dat'), 'translation.loader.ini' => array(0 => 'ini'), 'translation.loader.json' => array(0 => 'json')), array('cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/translations', 'debug' => true, 'resource_files' => array('af' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf'), 'ar' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ar.xlf'), 'az' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.az.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.az.xlf'), 'bg' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf'), 'ca' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ca.xlf'), 'cs' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.cs.xlf'), 'cy' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf'), 'da' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.da.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.da.xlf'), 'de' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.de.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.de.xlf'), 'el' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.el.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.el.xlf'), 'en' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.en.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.en.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.en.yml'), 'es' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.es.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.es.xlf'), 'et' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.et.xlf'), 'eu' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.eu.xlf'), 'fa' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.fa.xlf'), 'fi' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fi.xlf'), 'fr' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.fr.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/translations/messages.fr.yml', 4 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/translations/messages.fr.yml', 5 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.fr.yml', 6 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/validators.fr.yml', 7 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Resources/translations/messages.fr.xlf'), 'gl' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.gl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.gl.xlf'), 'he' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.he.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.he.xlf'), 'hr' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf'), 'hu' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.hu.xlf'), 'hy' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hy.xlf'), 'id' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.id.xlf'), 'it' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.it.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.it.xlf'), 'ja' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf'), 'lb' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lb.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.lb.xlf'), 'lt' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lt.xlf'), 'mn' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.mn.xlf'), 'nb' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.nb.xlf'), 'nl' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.nl.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/translations/messages.nl.yml', 4 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/translations/messages.nl.yml', 5 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.nl.yml', 6 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/validators.nl.yml'), 'no' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.no.xlf'), 'pl' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pl.xlf'), 'pt' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf'), 'pt_BR' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pt_BR.xlf'), 'ro' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ro.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ro.xlf'), 'ru' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ru.xlf'), 'sk' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sk.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sk.xlf'), 'sl' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sl.xlf'), 'sq' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf'), 'sr_Cyrl' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sr_Cyrl.xlf'), 'sr_Latn' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sr_Latn.xlf'), 'sv' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sv.xlf'), 'th' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf'), 'tr' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.tr.xlf'), 'uk' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf'), 'vi' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf'), 'zh_CN' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf'), 'zh_TW' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf'), 'lv' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf'), 'pt_PT' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pt_PT.xlf'), 'ua' => array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ua.xlf'))), array()); + $this->services['translator.default'] = $instance = new \Symfony\Bundle\FrameworkBundle\Translation\Translator($this, new \Symfony\Component\Translation\MessageSelector(), ['translation.loader.php' => [0 => 'php'], 'translation.loader.yml' => [0 => 'yml'], 'translation.loader.xliff' => [0 => 'xlf', 1 => 'xliff'], 'translation.loader.po' => [0 => 'po'], 'translation.loader.mo' => [0 => 'mo'], 'translation.loader.qt' => [0 => 'ts'], 'translation.loader.csv' => [0 => 'csv'], 'translation.loader.res' => [0 => 'res'], 'translation.loader.dat' => [0 => 'dat'], 'translation.loader.ini' => [0 => 'ini'], 'translation.loader.json' => [0 => 'json']], ['cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/translations', 'debug' => true, 'resource_files' => ['af' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf'], 'ar' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ar.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ar.xlf'], 'az' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.az.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.az.xlf'], 'bg' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.bg.xlf'], 'ca' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ca.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ca.xlf'], 'cs' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.cs.xlf'], 'cy' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf'], 'da' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.da.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.da.xlf'], 'de' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.de.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.de.xlf'], 'el' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.el.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.el.xlf'], 'en' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.en.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.en.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.en.yml'], 'es' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.es.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.es.xlf'], 'et' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.et.xlf'], 'eu' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.eu.xlf'], 'fa' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.fa.xlf'], 'fi' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fi.xlf'], 'fr' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.fr.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/translations/messages.fr.yml', 4 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/translations/messages.fr.yml', 5 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.fr.yml', 6 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/validators.fr.yml', 7 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Resources/translations/messages.fr.xlf'], 'gl' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.gl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.gl.xlf'], 'he' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.he.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.he.xlf'], 'hr' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf'], 'hu' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.hu.xlf'], 'hy' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.hy.xlf'], 'id' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.id.xlf'], 'it' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.it.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.it.xlf'], 'ja' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ja.xlf'], 'lb' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lb.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.lb.xlf'], 'lt' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lt.xlf'], 'mn' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.mn.xlf'], 'nb' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.nb.xlf'], 'nl' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.nl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.nl.xlf', 3 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/main/Resources/translations/messages.nl.yml', 4 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/custom-fields/Resources/translations/messages.nl.yml', 5 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/messages.nl.yml', 6 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/translations/validators.nl.yml'], 'no' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.no.xlf'], 'pl' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pl.xlf'], 'pt' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pt.xlf'], 'pt_BR' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.pt_BR.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pt_BR.xlf'], 'ro' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ro.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ro.xlf'], 'ru' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.ru.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ru.xlf'], 'sk' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sk.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sk.xlf'], 'sl' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sl.xlf'], 'sq' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf'], 'sr_Cyrl' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sr_Cyrl.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sr_Cyrl.xlf'], 'sr_Latn' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sr_Latn.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sr_Latn.xlf'], 'sv' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.sv.xlf', 2 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.sv.xlf'], 'th' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf'], 'tr' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.tr.xlf'], 'uk' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.uk.xlf'], 'vi' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf'], 'zh_CN' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf', 1 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.zh_CN.xlf'], 'zh_TW' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf'], 'lv' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/translations/validators.lv.xlf'], 'pt_PT' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.pt_PT.xlf'], 'ua' => [0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Exception/../Resources/translations/security.ua.xlf']]], []); - $instance->setFallbackLocales(array(0 => 'fr')); + $instance->setFallbackLocales([0 => 'fr']); return $instance; } @@ -3419,64 +4342,16 @@ class appDevDebugProjectContainer extends Container } /** - * Gets the 'twig' service. + * Gets the 'translator' service. * * This service is shared. * This method always returns the same instance of the service. * - * @return \Twig_Environment A Twig_Environment instance. + * @return \Symfony\Component\Translation\DataCollectorTranslator A Symfony\Component\Translation\DataCollectorTranslator instance. */ - protected function getTwigService() + protected function getTranslatorService() { - $a = $this->get('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE); - $b = $this->get('request_stack'); - $c = $this->get('fragment.handler'); - - $d = new \Symfony\Bridge\Twig\Extension\HttpFoundationExtension($b); - - $e = new \Symfony\Bridge\Twig\AppVariable(); - $e->setEnvironment('dev'); - $e->setDebug(true); - if ($this->has('security.token_storage')) { - $e->setTokenStorage($this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE)); - } - if ($this->has('request_stack')) { - $e->setRequestStack($b); - } - $e->setContainer($this); - - $this->services['twig'] = $instance = new \Twig_Environment($this->get('twig.loader'), array('form_themes' => array(0 => 'form_div_layout.html.twig', 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', 2 => 'ChillMainBundle:Form:fields.html.twig'), 'exception_controller' => 'twig.controller.exception:showAction', 'autoescape' => 'filename', 'cache' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/twig', 'charset' => 'UTF-8', 'debug' => true, 'paths' => array(), 'date' => array('format' => 'F j, Y H:i', 'interval_format' => '%d days', 'timezone' => NULL), 'number_format' => array('decimals' => 0, 'decimal_point' => '.', 'thousands_separator' => ','))); - - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\LogoutUrlExtension($this->get('security.logout_url_generator'))); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\SecurityExtension($this->get('security.authorization_checker', ContainerInterface::NULL_ON_INVALID_REFERENCE))); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\ProfilerExtension($this->get('twig.profile'), $a)); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\TranslationExtension($this->get('translator'))); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\AssetExtension($this->get('assets.packages'), $d)); - $instance->addExtension(new \Symfony\Bundle\TwigBundle\Extension\ActionsExtension($c)); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\CodeExtension(NULL, '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app', 'UTF-8')); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\RoutingExtension($this->get('router'))); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\YamlExtension()); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\StopwatchExtension($a, true)); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\ExpressionExtension()); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\HttpKernelExtension($c)); - $instance->addExtension($d); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\FormExtension(new \Symfony\Bridge\Twig\Form\TwigRenderer(new \Symfony\Bridge\Twig\Form\TwigRendererEngine(array(0 => 'form_div_layout.html.twig', 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', 2 => 'ChillMainBundle:Form:fields.html.twig')), $this->get('security.csrf.token_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE)))); - $instance->addExtension(new \Twig_Extension_Debug()); - $instance->addExtension(new \Symfony\Bundle\AsseticBundle\Twig\AsseticExtension($this->get('assetic.asset_factory'), $this->get('templating.name_parser'), false, array(), array(0 => 'ChillPersonBundle', 1 => 'ChillMainBundle'), new \Symfony\Bundle\AsseticBundle\DefaultValueSupplier($this))); - $instance->addExtension(new \Doctrine\Bundle\DoctrineBundle\Twig\DoctrineExtension()); - $instance->addExtension($this->get('chill.main.twig.chill_menu')); - $instance->addExtension($this->get('twig_intl')); - $instance->addExtension($this->get('chill.main.twig.translatable_string')); - $instance->addExtension($this->get('chill.main.twig.csv_cell')); - $instance->addExtension($this->get('chill.custom_field.twig.custom_fields_rendering')); - $instance->addExtension(new \Symfony\Bridge\Twig\Extension\DumpExtension($this->get('var_dumper.cloner'))); - $instance->addExtension(new \Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension()); - $instance->addGlobal('app', $e); - $instance->addGlobal('installation', array('name' => 'Chill')); - $instance->addGlobal('available_languages', array(0 => 'fr')); - call_user_func(array(new \Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator('F j, Y H:i', '%d days', NULL, 0, '.', ','), 'configure'), $instance); - - return $instance; + return $this->services['translator'] = new \Symfony\Component\Translation\DataCollectorTranslator(new \Symfony\Component\Translation\LoggingTranslator($this->get('translator.default'), $this->get('monolog.logger.translation'))); } /** @@ -3586,6 +4461,69 @@ class appDevDebugProjectContainer extends Container return $this->services['twig_intl'] = new \Twig_Extensions_Extension_Intl(); } + /** + * Gets the 'twig' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Twig_Environment A Twig_Environment instance. + */ + protected function getTwigService() + { + $a = $this->get('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE); + $b = $this->get('request_stack'); + $c = $this->get('fragment.handler'); + + $d = new \Symfony\Bridge\Twig\Extension\HttpFoundationExtension($b); + + $e = new \Symfony\Bridge\Twig\AppVariable(); + $e->setEnvironment('dev'); + $e->setDebug(true); + + if ($this->has('security.token_storage')) { + $e->setTokenStorage($this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE)); + } + + if ($this->has('request_stack')) { + $e->setRequestStack($b); + } + $e->setContainer($this); + + $this->services['twig'] = $instance = new \Twig_Environment($this->get('twig.loader'), ['form_themes' => [0 => 'form_div_layout.html.twig', 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', 2 => 'ChillMainBundle:Form:fields.html.twig'], 'exception_controller' => 'twig.controller.exception:showAction', 'autoescape' => 'filename', 'cache' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/twig', 'charset' => 'UTF-8', 'debug' => true, 'paths' => [], 'date' => ['format' => 'F j, Y H:i', 'interval_format' => '%d days', 'timezone' => null], 'number_format' => ['decimals' => 0, 'decimal_point' => '.', 'thousands_separator' => ',']]); + + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\LogoutUrlExtension($this->get('security.logout_url_generator'))); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\SecurityExtension($this->get('security.authorization_checker', ContainerInterface::NULL_ON_INVALID_REFERENCE))); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\ProfilerExtension($this->get('twig.profile'), $a)); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\TranslationExtension($this->get('translator'))); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\AssetExtension($this->get('assets.packages'), $d)); + $instance->addExtension(new \Symfony\Bundle\TwigBundle\Extension\ActionsExtension($c)); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\CodeExtension(null, '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app', 'UTF-8')); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\RoutingExtension($this->get('router'))); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\YamlExtension()); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\StopwatchExtension($a, true)); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\ExpressionExtension()); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\HttpKernelExtension($c)); + $instance->addExtension($d); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\FormExtension(new \Symfony\Bridge\Twig\Form\TwigRenderer(new \Symfony\Bridge\Twig\Form\TwigRendererEngine([0 => 'form_div_layout.html.twig', 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', 2 => 'ChillMainBundle:Form:fields.html.twig']), $this->get('security.csrf.token_manager', ContainerInterface::NULL_ON_INVALID_REFERENCE)))); + $instance->addExtension(new \Twig_Extension_Debug()); + $instance->addExtension(new \Symfony\Bundle\AsseticBundle\Twig\AsseticExtension($this->get('assetic.asset_factory'), $this->get('templating.name_parser'), false, [], [0 => 'ChillPersonBundle', 1 => 'ChillMainBundle'], new \Symfony\Bundle\AsseticBundle\DefaultValueSupplier($this))); + $instance->addExtension(new \Doctrine\Bundle\DoctrineBundle\Twig\DoctrineExtension()); + $instance->addExtension($this->get('chill.main.twig.chill_menu')); + $instance->addExtension($this->get('twig_intl')); + $instance->addExtension($this->get('chill.main.twig.translatable_string')); + $instance->addExtension($this->get('chill.main.twig.csv_cell')); + $instance->addExtension($this->get('chill.custom_field.twig.custom_fields_rendering')); + $instance->addExtension(new \Symfony\Bridge\Twig\Extension\DumpExtension($this->get('var_dumper.cloner'))); + $instance->addExtension(new \Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension()); + $instance->addGlobal('app', $e); + $instance->addGlobal('installation', ['name' => 'Chill']); + $instance->addGlobal('available_languages', [0 => 'fr']); + call_user_func([new \Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator('F j, Y H:i', '%d days', null, 0, '.', ','), 'configure'], $instance); + + return $instance; + } + /** * Gets the 'uri_signer' service. * @@ -3599,19 +4537,6 @@ class appDevDebugProjectContainer extends Container return $this->services['uri_signer'] = new \Symfony\Component\HttpKernel\UriSigner('Not very secret'); } - /** - * Gets the 'validator' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * @return \Symfony\Component\Validator\Validator\ValidatorInterface A Symfony\Component\Validator\Validator\ValidatorInterface instance. - */ - protected function getValidatorService() - { - return $this->services['validator'] = $this->get('validator.builder')->getValidator(); - } - /** * Gets the 'validator.builder' service. * @@ -3624,13 +4549,13 @@ class appDevDebugProjectContainer extends Container { $this->services['validator.builder'] = $instance = \Symfony\Component\Validator\Validation::createValidatorBuilder(); - $instance->setConstraintValidatorFactory(new \Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory($this, array('validator.expression' => 'validator.expression', 'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => 'validator.email', 'security.validator.user_password' => 'security.validator.user_password', 'doctrine.orm.validator.unique' => 'doctrine.orm.validator.unique'))); + $instance->setConstraintValidatorFactory(new \Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory($this, ['validator.expression' => 'validator.expression', 'Symfony\\Component\\Validator\\Constraints\\EmailValidator' => 'validator.email', 'security.validator.user_password' => 'security.validator.user_password', 'doctrine.orm.validator.unique' => 'doctrine.orm.validator.unique'])); $instance->setTranslator($this->get('translator')); $instance->setTranslationDomain('validators'); - $instance->addXmlMappings(array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/config/validation.xml')); - $instance->addYamlMappings(array(0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/config/validation.yml')); + $instance->addXmlMappings([0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/symfony/symfony/src/Symfony/Component/Form/Resources/config/validation.xml']); + $instance->addYamlMappings([0 => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/vendor/chill-project/person/Resources/config/validation.yml']); $instance->addMethodMapping('loadValidatorMetadata'); - $instance->addObjectInitializers(array(0 => $this->get('doctrine.orm.validator_initializer'))); + $instance->addObjectInitializers([0 => $this->get('doctrine.orm.validator_initializer')]); return $instance; } @@ -3661,6 +4586,19 @@ class appDevDebugProjectContainer extends Container return $this->services['validator.expression'] = new \Symfony\Component\Validator\Constraints\ExpressionValidator($this->get('property_accessor')); } + /** + * Gets the 'validator' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return \Symfony\Component\Validator\Validator\ValidatorInterface A Symfony\Component\Validator\Validator\ValidatorInterface instance. + */ + protected function getValidatorService() + { + return $this->services['validator'] = $this->get('validator.builder')->getValidator(); + } + /** * Gets the 'var_dumper.cli_dumper' service. * @@ -3671,7 +4609,7 @@ class appDevDebugProjectContainer extends Container */ protected function getVarDumper_CliDumperService() { - return $this->services['var_dumper.cli_dumper'] = new \Symfony\Component\VarDumper\Dumper\CliDumper(NULL, 'UTF-8'); + return $this->services['var_dumper.cli_dumper'] = new \Symfony\Component\VarDumper\Dumper\CliDumper(null, 'UTF-8'); } /** @@ -3715,7 +4653,7 @@ class appDevDebugProjectContainer extends Container */ protected function getWebProfiler_Controller_ProfilerService() { - return $this->services['web_profiler.controller.profiler'] = new \Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController($this->get('router', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('profiler', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('twig'), array('data_collector.config' => array(0 => 'config', 1 => '@WebProfiler/Collector/config.html.twig'), 'data_collector.request' => array(0 => 'request', 1 => '@WebProfiler/Collector/request.html.twig'), 'data_collector.ajax' => array(0 => 'ajax', 1 => '@WebProfiler/Collector/ajax.html.twig'), 'data_collector.exception' => array(0 => 'exception', 1 => '@WebProfiler/Collector/exception.html.twig'), 'data_collector.events' => array(0 => 'events', 1 => '@WebProfiler/Collector/events.html.twig'), 'data_collector.logger' => array(0 => 'logger', 1 => '@WebProfiler/Collector/logger.html.twig'), 'data_collector.time' => array(0 => 'time', 1 => '@WebProfiler/Collector/time.html.twig'), 'data_collector.memory' => array(0 => 'memory', 1 => '@WebProfiler/Collector/memory.html.twig'), 'data_collector.router' => array(0 => 'router', 1 => '@WebProfiler/Collector/router.html.twig'), 'data_collector.form' => array(0 => 'form', 1 => '@WebProfiler/Collector/form.html.twig'), 'data_collector.translation' => array(0 => 'translation', 1 => '@WebProfiler/Collector/translation.html.twig'), 'data_collector.twig' => array(0 => 'twig', 1 => '@WebProfiler/Collector/twig.html.twig'), 'data_collector.security' => array(0 => 'security', 1 => '@Security/Collector/security.html.twig'), 'swiftmailer.data_collector' => array(0 => 'swiftmailer', 1 => '@Swiftmailer/Collector/swiftmailer.html.twig'), 'data_collector.doctrine' => array(0 => 'db', 1 => '@Doctrine/Collector/db.html.twig'), 'data_collector.dump' => array(0 => 'dump', 1 => '@Debug/Profiler/dump.html.twig')), 'bottom'); + return $this->services['web_profiler.controller.profiler'] = new \Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController($this->get('router', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('profiler', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('twig'), ['data_collector.config' => [0 => 'config', 1 => '@WebProfiler/Collector/config.html.twig'], 'data_collector.request' => [0 => 'request', 1 => '@WebProfiler/Collector/request.html.twig'], 'data_collector.ajax' => [0 => 'ajax', 1 => '@WebProfiler/Collector/ajax.html.twig'], 'data_collector.exception' => [0 => 'exception', 1 => '@WebProfiler/Collector/exception.html.twig'], 'data_collector.events' => [0 => 'events', 1 => '@WebProfiler/Collector/events.html.twig'], 'data_collector.logger' => [0 => 'logger', 1 => '@WebProfiler/Collector/logger.html.twig'], 'data_collector.time' => [0 => 'time', 1 => '@WebProfiler/Collector/time.html.twig'], 'data_collector.memory' => [0 => 'memory', 1 => '@WebProfiler/Collector/memory.html.twig'], 'data_collector.router' => [0 => 'router', 1 => '@WebProfiler/Collector/router.html.twig'], 'data_collector.form' => [0 => 'form', 1 => '@WebProfiler/Collector/form.html.twig'], 'data_collector.translation' => [0 => 'translation', 1 => '@WebProfiler/Collector/translation.html.twig'], 'data_collector.twig' => [0 => 'twig', 1 => '@WebProfiler/Collector/twig.html.twig'], 'data_collector.security' => [0 => 'security', 1 => '@Security/Collector/security.html.twig'], 'swiftmailer.data_collector' => [0 => 'swiftmailer', 1 => '@Swiftmailer/Collector/swiftmailer.html.twig'], 'data_collector.doctrine' => [0 => 'db', 1 => '@Doctrine/Collector/db.html.twig'], 'data_collector.dump' => [0 => 'dump', 1 => '@Debug/Profiler/dump.html.twig']], 'bottom'); } /** @@ -3730,956 +4668,4 @@ class appDevDebugProjectContainer extends Container { return $this->services['web_profiler.controller.router'] = new \Symfony\Bundle\WebProfilerBundle\Controller\RouterController($this->get('profiler', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('twig'), $this->get('router', ContainerInterface::NULL_ON_INVALID_REFERENCE)); } - - /** - * Gets the 'assetic.asset_factory' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Bundle\AsseticBundle\Factory\AssetFactory A Symfony\Bundle\AsseticBundle\Factory\AssetFactory instance. - */ - protected function getAssetic_AssetFactoryService() - { - return $this->services['assetic.asset_factory'] = new \Symfony\Bundle\AsseticBundle\Factory\AssetFactory($this->get('kernel'), $this, $this->getParameterBag(), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', true); - } - - /** - * Gets the 'controller_name_converter' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser A Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser instance. - */ - protected function getControllerNameConverterService() - { - return $this->services['controller_name_converter'] = new \Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser($this->get('kernel')); - } - - /** - * Gets the 'doctrine.dbal.logger.profiling.default' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Doctrine\DBAL\Logging\DebugStack A Doctrine\DBAL\Logging\DebugStack instance. - */ - protected function getDoctrine_Dbal_Logger_Profiling_DefaultService() - { - return $this->services['doctrine.dbal.logger.profiling.default'] = new \Doctrine\DBAL\Logging\DebugStack(); - } - - /** - * Gets the 'router.request_context' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Routing\RequestContext A Symfony\Component\Routing\RequestContext instance. - */ - protected function getRouter_RequestContextService() - { - return $this->services['router.request_context'] = new \Symfony\Component\Routing\RequestContext('', 'GET', 'localhost', 'http', 80, 443); - } - - /** - * Gets the 'security.access.decision_manager' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\Authorization\AccessDecisionManager A Symfony\Component\Security\Core\Authorization\AccessDecisionManager instance. - */ - protected function getSecurity_Access_DecisionManagerService() - { - $a = $this->get('security.authentication.trust_resolver'); - $b = $this->get('security.role_hierarchy'); - - return $this->services['security.access.decision_manager'] = new \Symfony\Component\Security\Core\Authorization\AccessDecisionManager(array(0 => $this->get('chill.person.security.authorization.person'), 1 => new \Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter(new \Symfony\Component\Security\Core\Authorization\ExpressionLanguage(), $a, $b), 2 => new \Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter($b), 3 => new \Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter($a)), 'affirmative', false, true); - } - - /** - * Gets the 'security.authentication.manager' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager A Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager instance. - */ - protected function getSecurity_Authentication_ManagerService() - { - $this->services['security.authentication.manager'] = $instance = new \Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager(array(0 => new \Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider($this->get('security.user.provider.concrete.chain_provider'), new \Symfony\Component\Security\Core\User\UserChecker(), 'default', $this->get('security.encoder_factory'), true), 1 => new \Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider('5593aedf3be85')), true); - - $instance->setEventDispatcher($this->get('debug.event_dispatcher')); - - return $instance; - } - - /** - * Gets the 'security.authentication.trust_resolver' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver A Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver instance. - */ - protected function getSecurity_Authentication_TrustResolverService() - { - return $this->services['security.authentication.trust_resolver'] = new \Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver('Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken', 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken'); - } - - /** - * Gets the 'security.logout_url_generator' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Http\Logout\LogoutUrlGenerator A Symfony\Component\Security\Http\Logout\LogoutUrlGenerator instance. - */ - protected function getSecurity_LogoutUrlGeneratorService() - { - $this->services['security.logout_url_generator'] = $instance = new \Symfony\Component\Security\Http\Logout\LogoutUrlGenerator($this->get('request_stack', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('router', ContainerInterface::NULL_ON_INVALID_REFERENCE), $this->get('security.token_storage', ContainerInterface::NULL_ON_INVALID_REFERENCE)); - - $instance->registerListener('default', '/logout', 'logout', '_csrf_token', NULL); - - return $instance; - } - - /** - * Gets the 'security.role_hierarchy' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\Role\RoleHierarchy A Symfony\Component\Security\Core\Role\RoleHierarchy instance. - */ - protected function getSecurity_RoleHierarchyService() - { - return $this->services['security.role_hierarchy'] = new \Symfony\Component\Security\Core\Role\RoleHierarchy(array('CHILL_PERSON_UPDATE' => array(0 => 'CHILL_PERSON_SEE'), 'CHILL_PERSON_CREATE' => array(0 => 'CHILL_PERSON_SEE'))); - } - - /** - * Gets the 'security.user.provider.concrete.chain_provider' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\User\ChainUserProvider A Symfony\Component\Security\Core\User\ChainUserProvider instance. - */ - protected function getSecurity_User_Provider_Concrete_ChainProviderService() - { - return $this->services['security.user.provider.concrete.chain_provider'] = new \Symfony\Component\Security\Core\User\ChainUserProvider(array(0 => $this->get('security.user.provider.concrete.in_memory'), 1 => $this->get('security.user.provider.concrete.users'))); - } - - /** - * Gets the 'security.user.provider.concrete.in_memory' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\Security\Core\User\InMemoryUserProvider A Symfony\Component\Security\Core\User\InMemoryUserProvider instance. - */ - protected function getSecurity_User_Provider_Concrete_InMemoryService() - { - $this->services['security.user.provider.concrete.in_memory'] = $instance = new \Symfony\Component\Security\Core\User\InMemoryUserProvider(); - - $instance->createUser(new \Symfony\Component\Security\Core\User\User('admin', 'olala', array(0 => 'ROLE_ADMIN'))); - - return $instance; - } - - /** - * Gets the 'security.user.provider.concrete.users' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Bridge\Doctrine\Security\User\EntityUserProvider A Symfony\Bridge\Doctrine\Security\User\EntityUserProvider instance. - */ - protected function getSecurity_User_Provider_Concrete_UsersService() - { - return $this->services['security.user.provider.concrete.users'] = new \Symfony\Bridge\Doctrine\Security\User\EntityUserProvider($this->get('doctrine'), 'Chill\\MainBundle\\Entity\\User', 'username', NULL); - } - - /** - * Gets the 'session.storage.metadata_bag' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag A Symfony\Component\HttpFoundation\Session\Storage\MetadataBag instance. - */ - protected function getSession_Storage_MetadataBagService() - { - return $this->services['session.storage.metadata_bag'] = new \Symfony\Component\HttpFoundation\Session\Storage\MetadataBag('_sf2_meta', '0'); - } - - /** - * Gets the 'templating.locator' service. - * - * This service is shared. - * This method always returns the same instance of the service. - * - * This service is private. - * If you want to be able to request this service from the container directly, - * make it public, otherwise you might end up with broken code. - * - * @return \Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator A Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator instance. - */ - protected function getTemplating_LocatorService() - { - return $this->services['templating.locator'] = new \Symfony\Bundle\FrameworkBundle\Templating\Loader\TemplateLocator($this->get('file_locator'), '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev'); - } - - /** - * {@inheritdoc} - */ - public function getParameter($name) - { - $name = strtolower($name); - - if (!(isset($this->parameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - - return $this->parameters[$name]; - } - - /** - * {@inheritdoc} - */ - public function hasParameter($name) - { - $name = strtolower($name); - - return isset($this->parameters[$name]) || array_key_exists($name, $this->parameters); - } - - /** - * {@inheritdoc} - */ - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - /** - * {@inheritdoc} - */ - public function getParameterBag() - { - if (null === $this->parameterBag) { - $this->parameterBag = new FrozenParameterBag($this->parameters); - } - - return $this->parameterBag; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return array( - 'kernel.root_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app', - 'kernel.environment' => 'dev', - 'kernel.debug' => true, - 'kernel.name' => 'app', - 'kernel.cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev', - 'kernel.logs_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/logs', - 'kernel.bundles' => array( - 'FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle', - 'SecurityBundle' => 'Symfony\\Bundle\\SecurityBundle\\SecurityBundle', - 'TwigBundle' => 'Symfony\\Bundle\\TwigBundle\\TwigBundle', - 'MonologBundle' => 'Symfony\\Bundle\\MonologBundle\\MonologBundle', - 'SwiftmailerBundle' => 'Symfony\\Bundle\\SwiftmailerBundle\\SwiftmailerBundle', - 'AsseticBundle' => 'Symfony\\Bundle\\AsseticBundle\\AsseticBundle', - 'DoctrineBundle' => 'Doctrine\\Bundle\\DoctrineBundle\\DoctrineBundle', - 'SensioFrameworkExtraBundle' => 'Sensio\\Bundle\\FrameworkExtraBundle\\SensioFrameworkExtraBundle', - 'ChillMainBundle' => 'Chill\\MainBundle\\ChillMainBundle', - 'ChillCustomFieldsBundle' => 'Chill\\CustomFieldsBundle\\ChillCustomFieldsBundle', - 'ChillPersonBundle' => 'Chill\\PersonBundle\\ChillPersonBundle', - 'ChillActivityBundle' => 'Chill\\ActivityBundle\\ChillActivityBundle', - 'DebugBundle' => 'Symfony\\Bundle\\DebugBundle\\DebugBundle', - 'WebProfilerBundle' => 'Symfony\\Bundle\\WebProfilerBundle\\WebProfilerBundle', - 'SensioDistributionBundle' => 'Sensio\\Bundle\\DistributionBundle\\SensioDistributionBundle', - 'SensioGeneratorBundle' => 'Sensio\\Bundle\\GeneratorBundle\\SensioGeneratorBundle', - ), - 'kernel.charset' => 'UTF-8', - 'kernel.container_class' => 'appDevDebugProjectContainer', - 'database_host' => '127.0.0.1', - 'database_port' => 5432, - 'database_name' => 'chill_test', - 'database_user' => 'chill', - 'database_password' => 'chill', - 'locale' => 'fr', - 'controller_resolver.class' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver', - 'controller_name_converter.class' => 'Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerNameParser', - 'response_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ResponseListener', - 'streamed_response_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\StreamedResponseListener', - 'locale_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\LocaleListener', - 'event_dispatcher.class' => 'Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher', - 'http_kernel.class' => 'Symfony\\Component\\HttpKernel\\DependencyInjection\\ContainerAwareHttpKernel', - 'filesystem.class' => 'Symfony\\Component\\Filesystem\\Filesystem', - 'cache_warmer.class' => 'Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerAggregate', - 'cache_clearer.class' => 'Symfony\\Component\\HttpKernel\\CacheClearer\\ChainCacheClearer', - 'file_locator.class' => 'Symfony\\Component\\HttpKernel\\Config\\FileLocator', - 'uri_signer.class' => 'Symfony\\Component\\HttpKernel\\UriSigner', - 'request_stack.class' => 'Symfony\\Component\\HttpFoundation\\RequestStack', - 'fragment.handler.class' => 'Symfony\\Component\\HttpKernel\\DependencyInjection\\LazyLoadingFragmentHandler', - 'fragment.renderer.inline.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\InlineFragmentRenderer', - 'fragment.renderer.hinclude.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\HIncludeFragmentRenderer', - 'fragment.renderer.hinclude.global_template' => NULL, - 'fragment.renderer.esi.class' => 'Symfony\\Component\\HttpKernel\\Fragment\\EsiFragmentRenderer', - 'fragment.path' => '/_fragment', - 'translator.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\Translator', - 'translator.identity.class' => 'Symfony\\Component\\Translation\\IdentityTranslator', - 'translator.selector.class' => 'Symfony\\Component\\Translation\\MessageSelector', - 'translation.loader.php.class' => 'Symfony\\Component\\Translation\\Loader\\PhpFileLoader', - 'translation.loader.yml.class' => 'Symfony\\Component\\Translation\\Loader\\YamlFileLoader', - 'translation.loader.xliff.class' => 'Symfony\\Component\\Translation\\Loader\\XliffFileLoader', - 'translation.loader.po.class' => 'Symfony\\Component\\Translation\\Loader\\PoFileLoader', - 'translation.loader.mo.class' => 'Symfony\\Component\\Translation\\Loader\\MoFileLoader', - 'translation.loader.qt.class' => 'Symfony\\Component\\Translation\\Loader\\QtFileLoader', - 'translation.loader.csv.class' => 'Symfony\\Component\\Translation\\Loader\\CsvFileLoader', - 'translation.loader.res.class' => 'Symfony\\Component\\Translation\\Loader\\IcuResFileLoader', - 'translation.loader.dat.class' => 'Symfony\\Component\\Translation\\Loader\\IcuDatFileLoader', - 'translation.loader.ini.class' => 'Symfony\\Component\\Translation\\Loader\\IniFileLoader', - 'translation.loader.json.class' => 'Symfony\\Component\\Translation\\Loader\\JsonFileLoader', - 'translation.dumper.php.class' => 'Symfony\\Component\\Translation\\Dumper\\PhpFileDumper', - 'translation.dumper.xliff.class' => 'Symfony\\Component\\Translation\\Dumper\\XliffFileDumper', - 'translation.dumper.po.class' => 'Symfony\\Component\\Translation\\Dumper\\PoFileDumper', - 'translation.dumper.mo.class' => 'Symfony\\Component\\Translation\\Dumper\\MoFileDumper', - 'translation.dumper.yml.class' => 'Symfony\\Component\\Translation\\Dumper\\YamlFileDumper', - 'translation.dumper.qt.class' => 'Symfony\\Component\\Translation\\Dumper\\QtFileDumper', - 'translation.dumper.csv.class' => 'Symfony\\Component\\Translation\\Dumper\\CsvFileDumper', - 'translation.dumper.ini.class' => 'Symfony\\Component\\Translation\\Dumper\\IniFileDumper', - 'translation.dumper.json.class' => 'Symfony\\Component\\Translation\\Dumper\\JsonFileDumper', - 'translation.dumper.res.class' => 'Symfony\\Component\\Translation\\Dumper\\IcuResFileDumper', - 'translation.extractor.php.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\PhpExtractor', - 'translation.loader.class' => 'Symfony\\Bundle\\FrameworkBundle\\Translation\\TranslationLoader', - 'translation.extractor.class' => 'Symfony\\Component\\Translation\\Extractor\\ChainExtractor', - 'translation.writer.class' => 'Symfony\\Component\\Translation\\Writer\\TranslationWriter', - 'property_accessor.class' => 'Symfony\\Component\\PropertyAccess\\PropertyAccessor', - 'kernel.secret' => 'Not very secret', - 'kernel.http_method_override' => true, - 'kernel.trusted_hosts' => array( - - ), - 'kernel.trusted_proxies' => array( - - ), - 'kernel.default_locale' => 'fr', - 'test.client.class' => 'Symfony\\Bundle\\FrameworkBundle\\Client', - 'test.client.parameters' => array( - - ), - 'test.client.history.class' => 'Symfony\\Component\\BrowserKit\\History', - 'test.client.cookiejar.class' => 'Symfony\\Component\\BrowserKit\\CookieJar', - 'test.session.listener.class' => 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\TestSessionListener', - 'session.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Session', - 'session.flashbag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBag', - 'session.attribute_bag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag', - 'session.storage.metadata_bag.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\MetadataBag', - 'session.metadata.storage_key' => '_sf2_meta', - 'session.storage.native.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage', - 'session.storage.php_bridge.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\PhpBridgeSessionStorage', - 'session.storage.mock_file.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockFileSessionStorage', - 'session.handler.native_file.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeFileSessionHandler', - 'session.handler.write_check.class' => 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\WriteCheckSessionHandler', - 'session_listener.class' => 'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener', - 'session.storage.options' => array( - 'gc_probability' => 1, - ), - 'session.save_path' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/sessions', - 'session.metadata.update_threshold' => '0', - 'security.secure_random.class' => 'Symfony\\Component\\Security\\Core\\Util\\SecureRandom', - 'form.resolved_type_factory.class' => 'Symfony\\Component\\Form\\ResolvedFormTypeFactory', - 'form.registry.class' => 'Symfony\\Component\\Form\\FormRegistry', - 'form.factory.class' => 'Symfony\\Component\\Form\\FormFactory', - 'form.extension.class' => 'Symfony\\Component\\Form\\Extension\\DependencyInjection\\DependencyInjectionExtension', - 'form.type_guesser.validator.class' => 'Symfony\\Component\\Form\\Extension\\Validator\\ValidatorTypeGuesser', - 'form.type_extension.form.request_handler.class' => 'Symfony\\Component\\Form\\Extension\\HttpFoundation\\HttpFoundationRequestHandler', - 'form.type_extension.csrf.enabled' => true, - 'form.type_extension.csrf.field_name' => '_token', - 'security.csrf.token_generator.class' => 'Symfony\\Component\\Security\\Csrf\\TokenGenerator\\UriSafeTokenGenerator', - 'security.csrf.token_storage.class' => 'Symfony\\Component\\Security\\Csrf\\TokenStorage\\SessionTokenStorage', - 'security.csrf.token_manager.class' => 'Symfony\\Component\\Security\\Csrf\\CsrfTokenManager', - 'templating.engine.delegating.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\DelegatingEngine', - 'templating.name_parser.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateNameParser', - 'templating.filename_parser.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\TemplateFilenameParser', - 'templating.cache_warmer.template_paths.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\TemplatePathsCacheWarmer', - 'templating.locator.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\TemplateLocator', - 'templating.loader.filesystem.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Loader\\FilesystemLoader', - 'templating.loader.cache.class' => 'Symfony\\Component\\Templating\\Loader\\CacheLoader', - 'templating.loader.chain.class' => 'Symfony\\Component\\Templating\\Loader\\ChainLoader', - 'templating.finder.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\TemplateFinder', - 'templating.helper.assets.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\AssetsHelper', - 'templating.helper.router.class' => 'Symfony\\Bundle\\FrameworkBundle\\Templating\\Helper\\RouterHelper', - 'templating.helper.code.file_link_format' => NULL, - 'templating.loader.cache.path' => NULL, - 'templating.engines' => array( - 0 => 'twig', - ), - 'validator.class' => 'Symfony\\Component\\Validator\\Validator\\ValidatorInterface', - 'validator.builder.class' => 'Symfony\\Component\\Validator\\ValidatorBuilderInterface', - 'validator.builder.factory.class' => 'Symfony\\Component\\Validator\\Validation', - 'validator.mapping.cache.apc.class' => 'Symfony\\Component\\Validator\\Mapping\\Cache\\ApcCache', - 'validator.mapping.cache.prefix' => '', - 'validator.validator_factory.class' => 'Symfony\\Bundle\\FrameworkBundle\\Validator\\ConstraintValidatorFactory', - 'validator.expression.class' => 'Symfony\\Component\\Validator\\Constraints\\ExpressionValidator', - 'validator.email.class' => 'Symfony\\Component\\Validator\\Constraints\\EmailValidator', - 'validator.translation_domain' => 'validators', - 'validator.api' => '2.5-bc', - 'translator.logging' => true, - 'profiler.class' => 'Symfony\\Component\\HttpKernel\\Profiler\\Profiler', - 'profiler_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ProfilerListener', - 'data_collector.config.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\ConfigDataCollector', - 'data_collector.request.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\RequestDataCollector', - 'data_collector.exception.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\ExceptionDataCollector', - 'data_collector.events.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\EventDataCollector', - 'data_collector.logger.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\LoggerDataCollector', - 'data_collector.time.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\TimeDataCollector', - 'data_collector.memory.class' => 'Symfony\\Component\\HttpKernel\\DataCollector\\MemoryDataCollector', - 'data_collector.router.class' => 'Symfony\\Bundle\\FrameworkBundle\\DataCollector\\RouterDataCollector', - 'form.resolved_type_factory.data_collector_proxy.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\Proxy\\ResolvedTypeFactoryDataCollectorProxy', - 'form.type_extension.form.data_collector.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\Type\\DataCollectorTypeExtension', - 'data_collector.form.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\FormDataCollector', - 'data_collector.form.extractor.class' => 'Symfony\\Component\\Form\\Extension\\DataCollector\\FormDataExtractor', - 'profiler_listener.only_exceptions' => false, - 'profiler_listener.only_master_requests' => false, - 'profiler.storage.dsn' => 'file:/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/profiler', - 'profiler.storage.username' => '', - 'profiler.storage.password' => '', - 'profiler.storage.lifetime' => 86400, - 'router.class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\Router', - 'router.request_context.class' => 'Symfony\\Component\\Routing\\RequestContext', - 'routing.loader.class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader', - 'routing.resolver.class' => 'Symfony\\Component\\Config\\Loader\\LoaderResolver', - 'routing.loader.xml.class' => 'Symfony\\Component\\Routing\\Loader\\XmlFileLoader', - 'routing.loader.yml.class' => 'Symfony\\Component\\Routing\\Loader\\YamlFileLoader', - 'routing.loader.php.class' => 'Symfony\\Component\\Routing\\Loader\\PhpFileLoader', - 'router.options.generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', - 'router.options.generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', - 'router.options.generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', - 'router.options.matcher_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', - 'router.options.matcher_base_class' => 'Symfony\\Bundle\\FrameworkBundle\\Routing\\RedirectableUrlMatcher', - 'router.options.matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', - 'router.cache_warmer.class' => 'Symfony\\Bundle\\FrameworkBundle\\CacheWarmer\\RouterCacheWarmer', - 'router.options.matcher.cache_class' => 'appDevUrlMatcher', - 'router.options.generator.cache_class' => 'appDevUrlGenerator', - 'router_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\RouterListener', - 'router.request_context.host' => 'localhost', - 'router.request_context.scheme' => 'http', - 'router.request_context.base_url' => '', - 'router.resource' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/config/routing.yml', - 'router.cache_class_prefix' => 'appDev', - 'request_listener.http_port' => 80, - 'request_listener.https_port' => 443, - 'annotations.reader.class' => 'Doctrine\\Common\\Annotations\\AnnotationReader', - 'annotations.cached_reader.class' => 'Doctrine\\Common\\Annotations\\CachedReader', - 'annotations.file_cache_reader.class' => 'Doctrine\\Common\\Annotations\\FileCacheReader', - 'debug.debug_handlers_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\DebugHandlersListener', - 'debug.stopwatch.class' => 'Symfony\\Component\\Stopwatch\\Stopwatch', - 'debug.error_handler.throw_at' => -1, - 'debug.event_dispatcher.class' => 'Symfony\\Component\\HttpKernel\\Debug\\TraceableEventDispatcher', - 'debug.container.dump' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/appDevDebugProjectContainer.xml', - 'debug.controller_resolver.class' => 'Symfony\\Component\\HttpKernel\\Controller\\TraceableControllerResolver', - 'security.context.class' => 'Symfony\\Component\\Security\\Core\\SecurityContext', - 'security.user_checker.class' => 'Symfony\\Component\\Security\\Core\\User\\UserChecker', - 'security.encoder_factory.generic.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\EncoderFactory', - 'security.encoder.digest.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\MessageDigestPasswordEncoder', - 'security.encoder.plain.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\PlaintextPasswordEncoder', - 'security.encoder.pbkdf2.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\Pbkdf2PasswordEncoder', - 'security.encoder.bcrypt.class' => 'Symfony\\Component\\Security\\Core\\Encoder\\BCryptPasswordEncoder', - 'security.user.provider.in_memory.class' => 'Symfony\\Component\\Security\\Core\\User\\InMemoryUserProvider', - 'security.user.provider.in_memory.user.class' => 'Symfony\\Component\\Security\\Core\\User\\User', - 'security.user.provider.chain.class' => 'Symfony\\Component\\Security\\Core\\User\\ChainUserProvider', - 'security.authentication.trust_resolver.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationTrustResolver', - 'security.authentication.trust_resolver.anonymous_class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken', - 'security.authentication.trust_resolver.rememberme_class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken', - 'security.authentication.manager.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\AuthenticationProviderManager', - 'security.authentication.session_strategy.class' => 'Symfony\\Component\\Security\\Http\\Session\\SessionAuthenticationStrategy', - 'security.access.decision_manager.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\AccessDecisionManager', - 'security.access.simple_role_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleVoter', - 'security.access.authenticated_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\AuthenticatedVoter', - 'security.access.role_hierarchy_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\RoleHierarchyVoter', - 'security.access.expression_voter.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\Voter\\ExpressionVoter', - 'security.firewall.class' => 'Symfony\\Component\\Security\\Http\\Firewall', - 'security.firewall.map.class' => 'Symfony\\Bundle\\SecurityBundle\\Security\\FirewallMap', - 'security.firewall.context.class' => 'Symfony\\Bundle\\SecurityBundle\\Security\\FirewallContext', - 'security.matcher.class' => 'Symfony\\Component\\HttpFoundation\\RequestMatcher', - 'security.expression_matcher.class' => 'Symfony\\Component\\HttpFoundation\\ExpressionRequestMatcher', - 'security.role_hierarchy.class' => 'Symfony\\Component\\Security\\Core\\Role\\RoleHierarchy', - 'security.http_utils.class' => 'Symfony\\Component\\Security\\Http\\HttpUtils', - 'security.validator.user_password.class' => 'Symfony\\Component\\Security\\Core\\Validator\\Constraints\\UserPasswordValidator', - 'security.expression_language.class' => 'Symfony\\Component\\Security\\Core\\Authorization\\ExpressionLanguage', - 'security.authentication.retry_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\RetryAuthenticationEntryPoint', - 'security.channel_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ChannelListener', - 'security.authentication.form_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\FormAuthenticationEntryPoint', - 'security.authentication.listener.form.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\UsernamePasswordFormAuthenticationListener', - 'security.authentication.listener.simple_form.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SimpleFormAuthenticationListener', - 'security.authentication.listener.simple_preauth.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SimplePreAuthenticationListener', - 'security.authentication.listener.basic.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\BasicAuthenticationListener', - 'security.authentication.basic_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\BasicAuthenticationEntryPoint', - 'security.authentication.listener.digest.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\DigestAuthenticationListener', - 'security.authentication.digest_entry_point.class' => 'Symfony\\Component\\Security\\Http\\EntryPoint\\DigestAuthenticationEntryPoint', - 'security.authentication.listener.x509.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\X509AuthenticationListener', - 'security.authentication.listener.anonymous.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\AnonymousAuthenticationListener', - 'security.authentication.switchuser_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\SwitchUserListener', - 'security.logout_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\LogoutListener', - 'security.logout.handler.session.class' => 'Symfony\\Component\\Security\\Http\\Logout\\SessionLogoutHandler', - 'security.logout.handler.cookie_clearing.class' => 'Symfony\\Component\\Security\\Http\\Logout\\CookieClearingLogoutHandler', - 'security.logout.success_handler.class' => 'Symfony\\Component\\Security\\Http\\Logout\\DefaultLogoutSuccessHandler', - 'security.access_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\AccessListener', - 'security.access_map.class' => 'Symfony\\Component\\Security\\Http\\AccessMap', - 'security.exception_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ExceptionListener', - 'security.context_listener.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\ContextListener', - 'security.authentication.provider.dao.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\DaoAuthenticationProvider', - 'security.authentication.provider.simple.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\SimpleAuthenticationProvider', - 'security.authentication.provider.pre_authenticated.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\PreAuthenticatedAuthenticationProvider', - 'security.authentication.provider.anonymous.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\AnonymousAuthenticationProvider', - 'security.authentication.success_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\DefaultAuthenticationSuccessHandler', - 'security.authentication.failure_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\DefaultAuthenticationFailureHandler', - 'security.authentication.simple_success_failure_handler.class' => 'Symfony\\Component\\Security\\Http\\Authentication\\SimpleAuthenticationHandler', - 'security.authentication.provider.rememberme.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\Provider\\RememberMeAuthenticationProvider', - 'security.authentication.listener.rememberme.class' => 'Symfony\\Component\\Security\\Http\\Firewall\\RememberMeListener', - 'security.rememberme.token.provider.in_memory.class' => 'Symfony\\Component\\Security\\Core\\Authentication\\RememberMe\\InMemoryTokenProvider', - 'security.authentication.rememberme.services.persistent.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\PersistentTokenBasedRememberMeServices', - 'security.authentication.rememberme.services.simplehash.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\TokenBasedRememberMeServices', - 'security.rememberme.response_listener.class' => 'Symfony\\Component\\Security\\Http\\RememberMe\\ResponseListener', - 'templating.helper.logout_url.class' => 'Symfony\\Bundle\\SecurityBundle\\Templating\\Helper\\LogoutUrlHelper', - 'templating.helper.security.class' => 'Symfony\\Bundle\\SecurityBundle\\Templating\\Helper\\SecurityHelper', - 'twig.extension.logout_url.class' => 'Symfony\\Bridge\\Twig\\Extension\\LogoutUrlExtension', - 'twig.extension.security.class' => 'Symfony\\Bridge\\Twig\\Extension\\SecurityExtension', - 'data_collector.security.class' => 'Symfony\\Bundle\\SecurityBundle\\DataCollector\\SecurityDataCollector', - 'security.access.denied_url' => NULL, - 'security.authentication.manager.erase_credentials' => true, - 'security.authentication.session_strategy.strategy' => 'migrate', - 'security.access.always_authenticate_before_granting' => false, - 'security.authentication.hide_user_not_found' => true, - 'security.role_hierarchy.roles' => array( - 'CHILL_PERSON_UPDATE' => array( - 0 => 'CHILL_PERSON_SEE', - ), - 'CHILL_PERSON_CREATE' => array( - 0 => 'CHILL_PERSON_SEE', - ), - ), - 'twig.class' => 'Twig_Environment', - 'twig.loader.filesystem.class' => 'Symfony\\Bundle\\TwigBundle\\Loader\\FilesystemLoader', - 'twig.loader.chain.class' => 'Twig_Loader_Chain', - 'templating.engine.twig.class' => 'Symfony\\Bundle\\TwigBundle\\TwigEngine', - 'twig.cache_warmer.class' => 'Symfony\\Bundle\\TwigBundle\\CacheWarmer\\TemplateCacheCacheWarmer', - 'twig.extension.trans.class' => 'Symfony\\Bridge\\Twig\\Extension\\TranslationExtension', - 'twig.extension.actions.class' => 'Symfony\\Bundle\\TwigBundle\\Extension\\ActionsExtension', - 'twig.extension.code.class' => 'Symfony\\Bridge\\Twig\\Extension\\CodeExtension', - 'twig.extension.routing.class' => 'Symfony\\Bridge\\Twig\\Extension\\RoutingExtension', - 'twig.extension.yaml.class' => 'Symfony\\Bridge\\Twig\\Extension\\YamlExtension', - 'twig.extension.form.class' => 'Symfony\\Bridge\\Twig\\Extension\\FormExtension', - 'twig.extension.httpkernel.class' => 'Symfony\\Bridge\\Twig\\Extension\\HttpKernelExtension', - 'twig.extension.debug.stopwatch.class' => 'Symfony\\Bridge\\Twig\\Extension\\StopwatchExtension', - 'twig.extension.expression.class' => 'Symfony\\Bridge\\Twig\\Extension\\ExpressionExtension', - 'twig.form.engine.class' => 'Symfony\\Bridge\\Twig\\Form\\TwigRendererEngine', - 'twig.form.renderer.class' => 'Symfony\\Bridge\\Twig\\Form\\TwigRenderer', - 'twig.translation.extractor.class' => 'Symfony\\Bridge\\Twig\\Translation\\TwigExtractor', - 'twig.exception_listener.class' => 'Symfony\\Component\\HttpKernel\\EventListener\\ExceptionListener', - 'twig.controller.exception.class' => 'Symfony\\Bundle\\TwigBundle\\Controller\\ExceptionController', - 'twig.controller.preview_error.class' => 'Symfony\\Bundle\\TwigBundle\\Controller\\PreviewErrorController', - 'twig.exception_listener.controller' => 'twig.controller.exception:showAction', - 'twig.form.resources' => array( - 0 => 'form_div_layout.html.twig', - 1 => 'ChillCustomFieldsBundle:Form:fields.html.twig', - 2 => 'ChillMainBundle:Form:fields.html.twig', - ), - 'monolog.logger.class' => 'Symfony\\Bridge\\Monolog\\Logger', - 'monolog.gelf.publisher.class' => 'Gelf\\MessagePublisher', - 'monolog.gelfphp.publisher.class' => 'Gelf\\Publisher', - 'monolog.handler.stream.class' => 'Monolog\\Handler\\StreamHandler', - 'monolog.handler.console.class' => 'Symfony\\Bridge\\Monolog\\Handler\\ConsoleHandler', - 'monolog.handler.group.class' => 'Monolog\\Handler\\GroupHandler', - 'monolog.handler.buffer.class' => 'Monolog\\Handler\\BufferHandler', - 'monolog.handler.rotating_file.class' => 'Monolog\\Handler\\RotatingFileHandler', - 'monolog.handler.syslog.class' => 'Monolog\\Handler\\SyslogHandler', - 'monolog.handler.syslogudp.class' => 'Monolog\\Handler\\SyslogUdpHandler', - 'monolog.handler.null.class' => 'Monolog\\Handler\\NullHandler', - 'monolog.handler.test.class' => 'Monolog\\Handler\\TestHandler', - 'monolog.handler.gelf.class' => 'Monolog\\Handler\\GelfHandler', - 'monolog.handler.rollbar.class' => 'Monolog\\Handler\\RollbarHandler', - 'monolog.handler.flowdock.class' => 'Monolog\\Handler\\FlowdockHandler', - 'monolog.handler.browser_console.class' => 'Monolog\\Handler\\BrowserConsoleHandler', - 'monolog.handler.firephp.class' => 'Symfony\\Bridge\\Monolog\\Handler\\FirePHPHandler', - 'monolog.handler.chromephp.class' => 'Symfony\\Bridge\\Monolog\\Handler\\ChromePhpHandler', - 'monolog.handler.debug.class' => 'Symfony\\Bridge\\Monolog\\Handler\\DebugHandler', - 'monolog.handler.swift_mailer.class' => 'Symfony\\Bridge\\Monolog\\Handler\\SwiftMailerHandler', - 'monolog.handler.native_mailer.class' => 'Monolog\\Handler\\NativeMailerHandler', - 'monolog.handler.socket.class' => 'Monolog\\Handler\\SocketHandler', - 'monolog.handler.pushover.class' => 'Monolog\\Handler\\PushoverHandler', - 'monolog.handler.raven.class' => 'Monolog\\Handler\\RavenHandler', - 'monolog.handler.newrelic.class' => 'Monolog\\Handler\\NewRelicHandler', - 'monolog.handler.hipchat.class' => 'Monolog\\Handler\\HipChatHandler', - 'monolog.handler.slack.class' => 'Monolog\\Handler\\SlackHandler', - 'monolog.handler.cube.class' => 'Monolog\\Handler\\CubeHandler', - 'monolog.handler.amqp.class' => 'Monolog\\Handler\\AmqpHandler', - 'monolog.handler.error_log.class' => 'Monolog\\Handler\\ErrorLogHandler', - 'monolog.handler.loggly.class' => 'Monolog\\Handler\\LogglyHandler', - 'monolog.handler.logentries.class' => 'Monolog\\Handler\\LogEntriesHandler', - 'monolog.handler.whatfailuregroup.class' => 'Monolog\\Handler\\WhatFailureGroupHandler', - 'monolog.activation_strategy.not_found.class' => 'Symfony\\Bundle\\MonologBundle\\NotFoundActivationStrategy', - 'monolog.handler.fingers_crossed.class' => 'Monolog\\Handler\\FingersCrossedHandler', - 'monolog.handler.fingers_crossed.error_level_activation_strategy.class' => 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy', - 'monolog.handler.filter.class' => 'Monolog\\Handler\\FilterHandler', - 'monolog.handler.mongo.class' => 'Monolog\\Handler\\MongoDBHandler', - 'monolog.mongo.client.class' => 'MongoClient', - 'monolog.handler.elasticsearch.class' => 'Monolog\\Handler\\ElasticSearchHandler', - 'monolog.elastica.client.class' => 'Elastica\\Client', - 'monolog.swift_mailer.handlers' => array( - - ), - 'monolog.handlers_to_channels' => array( - - ), - 'swiftmailer.class' => 'Swift_Mailer', - 'swiftmailer.transport.sendmail.class' => 'Swift_Transport_SendmailTransport', - 'swiftmailer.transport.mail.class' => 'Swift_Transport_MailTransport', - 'swiftmailer.transport.failover.class' => 'Swift_Transport_FailoverTransport', - 'swiftmailer.plugin.redirecting.class' => 'Swift_Plugins_RedirectingPlugin', - 'swiftmailer.plugin.impersonate.class' => 'Swift_Plugins_ImpersonatePlugin', - 'swiftmailer.plugin.messagelogger.class' => 'Swift_Plugins_MessageLogger', - 'swiftmailer.plugin.antiflood.class' => 'Swift_Plugins_AntiFloodPlugin', - 'swiftmailer.transport.smtp.class' => 'Swift_Transport_EsmtpTransport', - 'swiftmailer.plugin.blackhole.class' => 'Swift_Plugins_BlackholePlugin', - 'swiftmailer.spool.file.class' => 'Swift_FileSpool', - 'swiftmailer.spool.memory.class' => 'Swift_MemorySpool', - 'swiftmailer.email_sender.listener.class' => 'Symfony\\Bundle\\SwiftmailerBundle\\EventListener\\EmailSenderListener', - 'swiftmailer.data_collector.class' => 'Symfony\\Bundle\\SwiftmailerBundle\\DataCollector\\MessageDataCollector', - 'swiftmailer.mailer.default.transport.name' => 'smtp', - 'swiftmailer.mailer.default.delivery.enabled' => true, - 'swiftmailer.mailer.default.transport.smtp.encryption' => NULL, - 'swiftmailer.mailer.default.transport.smtp.port' => 25, - 'swiftmailer.mailer.default.transport.smtp.host' => 'localhost', - 'swiftmailer.mailer.default.transport.smtp.username' => NULL, - 'swiftmailer.mailer.default.transport.smtp.password' => NULL, - 'swiftmailer.mailer.default.transport.smtp.auth_mode' => NULL, - 'swiftmailer.mailer.default.transport.smtp.timeout' => 30, - 'swiftmailer.mailer.default.transport.smtp.source_ip' => NULL, - 'swiftmailer.mailer.default.spool.enabled' => false, - 'swiftmailer.mailer.default.plugin.impersonate' => NULL, - 'swiftmailer.mailer.default.single_address' => NULL, - 'swiftmailer.spool.enabled' => false, - 'swiftmailer.delivery.enabled' => true, - 'swiftmailer.single_address' => NULL, - 'swiftmailer.mailers' => array( - 'default' => 'swiftmailer.mailer.default', - ), - 'swiftmailer.default_mailer' => 'default', - 'assetic.asset_factory.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\AssetFactory', - 'assetic.asset_manager.class' => 'Assetic\\Factory\\LazyAssetManager', - 'assetic.asset_manager_cache_warmer.class' => 'Symfony\\Bundle\\AsseticBundle\\CacheWarmer\\AssetManagerCacheWarmer', - 'assetic.cached_formula_loader.class' => 'Assetic\\Factory\\Loader\\CachedFormulaLoader', - 'assetic.config_cache.class' => 'Assetic\\Cache\\ConfigCache', - 'assetic.config_loader.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Loader\\ConfigurationLoader', - 'assetic.config_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\ConfigurationResource', - 'assetic.coalescing_directory_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\CoalescingDirectoryResource', - 'assetic.directory_resource.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Resource\\DirectoryResource', - 'assetic.filter_manager.class' => 'Symfony\\Bundle\\AsseticBundle\\FilterManager', - 'assetic.worker.ensure_filter.class' => 'Assetic\\Factory\\Worker\\EnsureFilterWorker', - 'assetic.worker.cache_busting.class' => 'Assetic\\Factory\\Worker\\CacheBustingWorker', - 'assetic.value_supplier.class' => 'Symfony\\Bundle\\AsseticBundle\\DefaultValueSupplier', - 'assetic.node.paths' => array( - - ), - 'assetic.cache_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/assetic', - 'assetic.bundles' => array( - 0 => 'ChillPersonBundle', - 1 => 'ChillMainBundle', - ), - 'assetic.twig_extension.class' => 'Symfony\\Bundle\\AsseticBundle\\Twig\\AsseticExtension', - 'assetic.twig_formula_loader.class' => 'Assetic\\Extension\\Twig\\TwigFormulaLoader', - 'assetic.helper.dynamic.class' => 'Symfony\\Bundle\\AsseticBundle\\Templating\\DynamicAsseticHelper', - 'assetic.helper.static.class' => 'Symfony\\Bundle\\AsseticBundle\\Templating\\StaticAsseticHelper', - 'assetic.php_formula_loader.class' => 'Symfony\\Bundle\\AsseticBundle\\Factory\\Loader\\AsseticHelperFormulaLoader', - 'assetic.debug' => true, - 'assetic.use_controller' => false, - 'assetic.enable_profiler' => false, - 'assetic.read_from' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', - 'assetic.write_to' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/../web', - 'assetic.variables' => array( - - ), - 'assetic.java.bin' => '/usr/bin/java', - 'assetic.node.bin' => '/usr/local/bin/node', - 'assetic.ruby.bin' => '/usr/local/opt/ruby/bin/ruby', - 'assetic.sass.bin' => '/usr/local/bin/sass', - 'assetic.filter.cssrewrite.class' => 'Assetic\\Filter\\CssRewriteFilter', - 'assetic.twig_extension.functions' => array( - - ), - 'doctrine_cache.apc.class' => 'Doctrine\\Common\\Cache\\ApcCache', - 'doctrine_cache.array.class' => 'Doctrine\\Common\\Cache\\ArrayCache', - 'doctrine_cache.file_system.class' => 'Doctrine\\Common\\Cache\\FilesystemCache', - 'doctrine_cache.php_file.class' => 'Doctrine\\Common\\Cache\\PhpFileCache', - 'doctrine_cache.mongodb.class' => 'Doctrine\\Common\\Cache\\MongoDBCache', - 'doctrine_cache.mongodb.collection.class' => 'MongoCollection', - 'doctrine_cache.mongodb.connection.class' => 'MongoClient', - 'doctrine_cache.mongodb.server' => 'localhost:27017', - 'doctrine_cache.riak.class' => 'Doctrine\\Common\\Cache\\RiakCache', - 'doctrine_cache.riak.bucket.class' => 'Riak\\Bucket', - 'doctrine_cache.riak.connection.class' => 'Riak\\Connection', - 'doctrine_cache.riak.bucket_property_list.class' => 'Riak\\BucketPropertyList', - 'doctrine_cache.riak.host' => 'localhost', - 'doctrine_cache.riak.port' => 8087, - 'doctrine_cache.memcache.class' => 'Doctrine\\Common\\Cache\\MemcacheCache', - 'doctrine_cache.memcache.connection.class' => 'Memcache', - 'doctrine_cache.memcache.host' => 'localhost', - 'doctrine_cache.memcache.port' => 11211, - 'doctrine_cache.memcached.class' => 'Doctrine\\Common\\Cache\\MemcachedCache', - 'doctrine_cache.memcached.connection.class' => 'Memcached', - 'doctrine_cache.memcached.host' => 'localhost', - 'doctrine_cache.memcached.port' => 11211, - 'doctrine_cache.redis.class' => 'Doctrine\\Common\\Cache\\RedisCache', - 'doctrine_cache.redis.connection.class' => 'Redis', - 'doctrine_cache.redis.host' => 'localhost', - 'doctrine_cache.redis.port' => 6379, - 'doctrine_cache.couchbase.class' => 'Doctrine\\Common\\Cache\\CouchbaseCache', - 'doctrine_cache.couchbase.connection.class' => 'Couchbase', - 'doctrine_cache.couchbase.hostnames' => 'localhost:8091', - 'doctrine_cache.wincache.class' => 'Doctrine\\Common\\Cache\\WinCacheCache', - 'doctrine_cache.xcache.class' => 'Doctrine\\Common\\Cache\\XcacheCache', - 'doctrine_cache.zenddata.class' => 'Doctrine\\Common\\Cache\\ZendDataCache', - 'doctrine_cache.security.acl.cache.class' => 'Doctrine\\Bundle\\DoctrineCacheBundle\\Acl\\Model\\AclCache', - 'doctrine.dbal.logger.chain.class' => 'Doctrine\\DBAL\\Logging\\LoggerChain', - 'doctrine.dbal.logger.profiling.class' => 'Doctrine\\DBAL\\Logging\\DebugStack', - 'doctrine.dbal.logger.class' => 'Symfony\\Bridge\\Doctrine\\Logger\\DbalLogger', - 'doctrine.dbal.configuration.class' => 'Doctrine\\DBAL\\Configuration', - 'doctrine.data_collector.class' => 'Doctrine\\Bundle\\DoctrineBundle\\DataCollector\\DoctrineDataCollector', - 'doctrine.dbal.connection.event_manager.class' => 'Symfony\\Bridge\\Doctrine\\ContainerAwareEventManager', - 'doctrine.dbal.connection_factory.class' => 'Doctrine\\Bundle\\DoctrineBundle\\ConnectionFactory', - 'doctrine.dbal.events.mysql_session_init.class' => 'Doctrine\\DBAL\\Event\\Listeners\\MysqlSessionInit', - 'doctrine.dbal.events.oracle_session_init.class' => 'Doctrine\\DBAL\\Event\\Listeners\\OracleSessionInit', - 'doctrine.class' => 'Doctrine\\Bundle\\DoctrineBundle\\Registry', - 'doctrine.entity_managers' => array( - 'default' => 'doctrine.orm.default_entity_manager', - ), - 'doctrine.default_entity_manager' => 'default', - 'doctrine.dbal.connection_factory.types' => array( - - ), - 'doctrine.connections' => array( - 'default' => 'doctrine.dbal.default_connection', - ), - 'doctrine.default_connection' => 'default', - 'doctrine.orm.configuration.class' => 'Doctrine\\ORM\\Configuration', - 'doctrine.orm.entity_manager.class' => 'Doctrine\\ORM\\EntityManager', - 'doctrine.orm.manager_configurator.class' => 'Doctrine\\Bundle\\DoctrineBundle\\ManagerConfigurator', - 'doctrine.orm.cache.array.class' => 'Doctrine\\Common\\Cache\\ArrayCache', - 'doctrine.orm.cache.apc.class' => 'Doctrine\\Common\\Cache\\ApcCache', - 'doctrine.orm.cache.memcache.class' => 'Doctrine\\Common\\Cache\\MemcacheCache', - 'doctrine.orm.cache.memcache_host' => 'localhost', - 'doctrine.orm.cache.memcache_port' => 11211, - 'doctrine.orm.cache.memcache_instance.class' => 'Memcache', - 'doctrine.orm.cache.memcached.class' => 'Doctrine\\Common\\Cache\\MemcachedCache', - 'doctrine.orm.cache.memcached_host' => 'localhost', - 'doctrine.orm.cache.memcached_port' => 11211, - 'doctrine.orm.cache.memcached_instance.class' => 'Memcached', - 'doctrine.orm.cache.redis.class' => 'Doctrine\\Common\\Cache\\RedisCache', - 'doctrine.orm.cache.redis_host' => 'localhost', - 'doctrine.orm.cache.redis_port' => 6379, - 'doctrine.orm.cache.redis_instance.class' => 'Redis', - 'doctrine.orm.cache.xcache.class' => 'Doctrine\\Common\\Cache\\XcacheCache', - 'doctrine.orm.cache.wincache.class' => 'Doctrine\\Common\\Cache\\WinCacheCache', - 'doctrine.orm.cache.zenddata.class' => 'Doctrine\\Common\\Cache\\ZendDataCache', - 'doctrine.orm.metadata.driver_chain.class' => 'Doctrine\\Common\\Persistence\\Mapping\\Driver\\MappingDriverChain', - 'doctrine.orm.metadata.annotation.class' => 'Doctrine\\ORM\\Mapping\\Driver\\AnnotationDriver', - 'doctrine.orm.metadata.xml.class' => 'Doctrine\\ORM\\Mapping\\Driver\\SimplifiedXmlDriver', - 'doctrine.orm.metadata.yml.class' => 'Doctrine\\ORM\\Mapping\\Driver\\SimplifiedYamlDriver', - 'doctrine.orm.metadata.php.class' => 'Doctrine\\ORM\\Mapping\\Driver\\PHPDriver', - 'doctrine.orm.metadata.staticphp.class' => 'Doctrine\\ORM\\Mapping\\Driver\\StaticPHPDriver', - 'doctrine.orm.proxy_cache_warmer.class' => 'Symfony\\Bridge\\Doctrine\\CacheWarmer\\ProxyCacheWarmer', - 'form.type_guesser.doctrine.class' => 'Symfony\\Bridge\\Doctrine\\Form\\DoctrineOrmTypeGuesser', - 'doctrine.orm.validator.unique.class' => 'Symfony\\Bridge\\Doctrine\\Validator\\Constraints\\UniqueEntityValidator', - 'doctrine.orm.validator_initializer.class' => 'Symfony\\Bridge\\Doctrine\\Validator\\DoctrineInitializer', - 'doctrine.orm.security.user.provider.class' => 'Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider', - 'doctrine.orm.listeners.resolve_target_entity.class' => 'Doctrine\\ORM\\Tools\\ResolveTargetEntityListener', - 'doctrine.orm.listeners.attach_entity_listeners.class' => 'Doctrine\\ORM\\Tools\\AttachEntityListenersListener', - 'doctrine.orm.naming_strategy.default.class' => 'Doctrine\\ORM\\Mapping\\DefaultNamingStrategy', - 'doctrine.orm.naming_strategy.underscore.class' => 'Doctrine\\ORM\\Mapping\\UnderscoreNamingStrategy', - 'doctrine.orm.quote_strategy.default.class' => 'Doctrine\\ORM\\Mapping\\DefaultQuoteStrategy', - 'doctrine.orm.quote_strategy.ansi.class' => 'Doctrine\\ORM\\Mapping\\AnsiQuoteStrategy', - 'doctrine.orm.entity_listener_resolver.class' => 'Doctrine\\ORM\\Mapping\\DefaultEntityListenerResolver', - 'doctrine.orm.second_level_cache.default_cache_factory.class' => 'Doctrine\\ORM\\Cache\\DefaultCacheFactory', - 'doctrine.orm.second_level_cache.default_region.class' => 'Doctrine\\ORM\\Cache\\Region\\DefaultRegion', - 'doctrine.orm.second_level_cache.filelock_region.class' => 'Doctrine\\ORM\\Cache\\Region\\FileLockRegion', - 'doctrine.orm.second_level_cache.logger_chain.class' => 'Doctrine\\ORM\\Cache\\Logging\\CacheLoggerChain', - 'doctrine.orm.second_level_cache.logger_statistics.class' => 'Doctrine\\ORM\\Cache\\Logging\\StatisticsCacheLogger', - 'doctrine.orm.second_level_cache.cache_configuration.class' => 'Doctrine\\ORM\\Cache\\CacheConfiguration', - 'doctrine.orm.second_level_cache.regions_configuration.class' => 'Doctrine\\ORM\\Cache\\RegionsConfiguration', - 'doctrine.orm.auto_generate_proxy_classes' => true, - 'doctrine.orm.proxy_dir' => '/Users/marcu/Projects/Chill/vendor/chill-project/activity/Tests/Fixtures/App/app/cache/dev/doctrine/orm/Proxies', - 'doctrine.orm.proxy_namespace' => 'Proxies', - 'sensio_framework_extra.view.guesser.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Templating\\TemplateGuesser', - 'sensio_framework_extra.controller.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\ControllerListener', - 'sensio_framework_extra.routing.loader.annot_dir.class' => 'Symfony\\Component\\Routing\\Loader\\AnnotationDirectoryLoader', - 'sensio_framework_extra.routing.loader.annot_file.class' => 'Symfony\\Component\\Routing\\Loader\\AnnotationFileLoader', - 'sensio_framework_extra.routing.loader.annot_class.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Routing\\AnnotatedRouteControllerLoader', - 'sensio_framework_extra.converter.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\ParamConverterListener', - 'sensio_framework_extra.converter.manager.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\ParamConverterManager', - 'sensio_framework_extra.converter.doctrine.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\DoctrineParamConverter', - 'sensio_framework_extra.converter.datetime.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\Request\\ParamConverter\\DateTimeParamConverter', - 'sensio_framework_extra.view.listener.class' => 'Sensio\\Bundle\\FrameworkExtraBundle\\EventListener\\TemplateListener', - 'chill_main.installation_name' => 'Chill', - 'chill_main.available_languages' => array( - 0 => 'fr', - ), - 'chill_main.routing.resources' => array( - 0 => '@ChillPersonBundle/Resources/config/routing.yml', - 1 => '@ChillCustomFieldsBundle/Resources/config/routing.yml', - 2 => '@ChillMainBundle/Resources/config/routing.yml', - ), - 'chill_custom_fields.customizables_entities' => array( - 0 => array( - 'class' => 'Chill\\PersonBundle\\Entity\\Person', - 'name' => 'PersonEntity', - 'options' => array( - - ), - ), - ), - 'cl_chill_person.search.use_double_metaphone' => false, - 'web_profiler.controller.profiler.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\ProfilerController', - 'web_profiler.controller.router.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\RouterController', - 'web_profiler.controller.exception.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Controller\\ExceptionController', - 'twig.extension.webprofiler.class' => 'Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension', - 'web_profiler.debug_toolbar.position' => 'bottom', - 'sensio_distribution.webconfigurator.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Configurator', - 'sensio_distribution.webconfigurator.doctrine_step.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Step\\DoctrineStep', - 'sensio_distribution.webconfigurator.secret_step.class' => 'Sensio\\Bundle\\DistributionBundle\\Configurator\\Step\\SecretStep', - 'sensio_distribution.security_checker.class' => 'SensioLabs\\Security\\SecurityChecker', - 'sensio_distribution.security_checker.command.class' => 'SensioLabs\\Security\\Command\\SecurityCheckerCommand', - 'data_collector.templates' => array( - 'data_collector.config' => array( - 0 => 'config', - 1 => '@WebProfiler/Collector/config.html.twig', - ), - 'data_collector.request' => array( - 0 => 'request', - 1 => '@WebProfiler/Collector/request.html.twig', - ), - 'data_collector.ajax' => array( - 0 => 'ajax', - 1 => '@WebProfiler/Collector/ajax.html.twig', - ), - 'data_collector.exception' => array( - 0 => 'exception', - 1 => '@WebProfiler/Collector/exception.html.twig', - ), - 'data_collector.events' => array( - 0 => 'events', - 1 => '@WebProfiler/Collector/events.html.twig', - ), - 'data_collector.logger' => array( - 0 => 'logger', - 1 => '@WebProfiler/Collector/logger.html.twig', - ), - 'data_collector.time' => array( - 0 => 'time', - 1 => '@WebProfiler/Collector/time.html.twig', - ), - 'data_collector.memory' => array( - 0 => 'memory', - 1 => '@WebProfiler/Collector/memory.html.twig', - ), - 'data_collector.router' => array( - 0 => 'router', - 1 => '@WebProfiler/Collector/router.html.twig', - ), - 'data_collector.form' => array( - 0 => 'form', - 1 => '@WebProfiler/Collector/form.html.twig', - ), - 'data_collector.translation' => array( - 0 => 'translation', - 1 => '@WebProfiler/Collector/translation.html.twig', - ), - 'data_collector.twig' => array( - 0 => 'twig', - 1 => '@WebProfiler/Collector/twig.html.twig', - ), - 'data_collector.security' => array( - 0 => 'security', - 1 => '@Security/Collector/security.html.twig', - ), - 'swiftmailer.data_collector' => array( - 0 => 'swiftmailer', - 1 => '@Swiftmailer/Collector/swiftmailer.html.twig', - ), - 'data_collector.doctrine' => array( - 0 => 'db', - 1 => '@Doctrine/Collector/db.html.twig', - ), - 'data_collector.dump' => array( - 0 => 'dump', - 1 => '@Debug/Profiler/dump.html.twig', - ), - ), - 'console.command.ids' => array( - 0 => 'sensio_distribution.security_checker.command', - ), - ); - } } diff --git a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/web/app_dev.php b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/web/app_dev.php index e0279c2ae..773037aa3 100644 --- a/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/web/app_dev.php +++ b/src/Bundle/ChillActivityBundle/Resources/test/Fixtures/App/web/app_dev.php @@ -1,7 +1,14 @@ loadClassCache(); diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php index 93d8117a9..d3452d7bc 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityStatsVoter.php @@ -1,92 +1,80 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Security\Authorization; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Chill\MainBundle\Entity\Center; -/** - * - * - * @author Julien Fastré - */ +use function in_array; + class ActivityStatsVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const STATS = 'CHILL_ACTIVITY_STATS'; - const LISTS = 'CHILL_ACTIVITY_LIST'; - + public const LISTS = 'CHILL_ACTIVITY_LIST'; + + public const STATS = 'CHILL_ACTIVITY_STATS'; + /** - * * @var AuthorizationHelper */ protected $helper; - + public function __construct(AuthorizationHelper $helper) { $this->helper = $helper; } - private function getAttributes() - { - return array(self::STATS, self::LISTS); - } - - protected function getSupportedClasses() - { - return array(Center::class); - } - - protected function supports($attribute, $subject) - { - if ($subject instanceof Center - && \in_array($attribute, $this->getAttributes())) { - - return true; - } - - return false; - } - - protected function isGranted($attribute, $object, $user = null) - { - if (!$user instanceof \Symfony\Component\Security\Core\User\UserInterface) { - return false; - } - - return $this->helper->userHasAccess($user, $object, $attribute); - } - public function getRoles() { return $this->getAttributes(); } + public function getRolesWithHierarchy() + { + return ['Activity' => $this->getRoles()]; + } + public function getRolesWithoutScope() { return $this->getAttributes(); } - public function getRolesWithHierarchy() + protected function getSupportedClasses() { - return [ 'Activity' => $this->getRoles() ]; + return [Center::class]; + } + + protected function isGranted($attribute, $object, $user = null) + { + if (!$user instanceof \Symfony\Component\Security\Core\User\UserInterface) { + return false; + } + + return $this->helper->userHasAccess($user, $object, $attribute); + } + + protected function supports($attribute, $subject) + { + if ( + $subject instanceof Center + && in_array($attribute, $this->getAttributes()) + ) { + return true; + } + + return false; + } + + private function getAttributes() + { + return [self::STATS, self::LISTS]; } } diff --git a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php index 79cb6d852..cc3e62613 100644 --- a/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php +++ b/src/Bundle/ChillActivityBundle/Security/Authorization/ActivityVoter.php @@ -1,49 +1,38 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Security\Authorization; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - +use Chill\ActivityBundle\Entity\Activity; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Chill\MainBundle\Entity\User; -use Chill\ActivityBundle\Entity\Activity; use Chill\PersonBundle\Entity\Person; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ +use function in_array; + class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_ACTIVITY_CREATE'; - const SEE = 'CHILL_ACTIVITY_SEE'; - const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS'; - const UPDATE = 'CHILL_ACTIVITY_UPDATE'; - const DELETE = 'CHILL_ACTIVITY_DELETE'; + public const CREATE = 'CHILL_ACTIVITY_CREATE'; + + public const DELETE = 'CHILL_ACTIVITY_DELETE'; + + public const SEE = 'CHILL_ACTIVITY_SEE'; + + public const SEE_DETAILS = 'CHILL_ACTIVITY_SEE_DETAILS'; + + public const UPDATE = 'CHILL_ACTIVITY_UPDATE'; /** - * * @var AuthorizationHelper */ protected $helper; @@ -53,18 +42,33 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn $this->helper = $helper; } + public function getRoles() + { + return $this->getAttributes(); + } + + public function getRolesWithHierarchy() + { + return ['Activity' => $this->getRoles()]; + } + + public function getRolesWithoutScope() + { + return []; + } protected function supports($attribute, $subject) { if ($subject instanceof Activity) { - return \in_array($attribute, $this->getAttributes()); - } elseif ($subject instanceof Person) { - return $attribute === self::SEE - || - $attribute === self::CREATE; - } else { - return false; + return in_array($attribute, $this->getAttributes()); } + + if ($subject instanceof Person) { + return self::SEE === $attribute + || self::CREATE === $attribute; + } + + return false; } protected function voteOnAttribute($attribute, $subject, TokenInterface $token) @@ -72,38 +76,20 @@ class ActivityVoter extends AbstractChillVoter implements ProvideRoleHierarchyIn if (!$token->getUser() instanceof User) { return false; } - + if ($subject instanceof Person) { $centers = $this->helper->getReachableCenters($token->getUser(), new Role($attribute)); - - return \in_array($subject->getCenter(), $centers); + + return in_array($subject->getCenter(), $centers); } - + /* @var $subject Activity */ return $this->helper->userHasAccess($token->getUser(), $subject, $attribute); } - + private function getAttributes() { - return [ self::CREATE, self::SEE, self::UPDATE, self::DELETE, - self::SEE_DETAILS ]; + return [self::CREATE, self::SEE, self::UPDATE, self::DELETE, + self::SEE_DETAILS, ]; } - - - public function getRoles() - { - return $this->getAttributes(); - } - - public function getRolesWithoutScope() - { - return array(); - } - - - public function getRolesWithHierarchy() - { - return [ 'Activity' => $this->getRoles() ]; - } - } diff --git a/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php b/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php index 1e9845acd..a6a25530f 100644 --- a/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php +++ b/src/Bundle/ChillActivityBundle/Templating/Entity/ActivityReasonRender.php @@ -1,82 +1,65 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\ActivityBundle\Templating\Entity; -use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; use Chill\ActivityBundle\Entity\ActivityReason; +use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; use Chill\MainBundle\Templating\TranslatableStringHelper; /** - * Render activity reason - * + * Render activity reason. */ class ActivityReasonRender extends AbstractChillEntityRender { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct(TranslatableStringHelper $translatableStringHelper) { $this->translatableStringHelper = $translatableStringHelper; } - public function renderBox($entity, array $options): string { return - $this->getDefaultOpeningBox('activity-reason'). - ' '. - ''. + $this->getDefaultOpeningBox('activity-reason') . + ' ' . + '' . $this->translatableStringHelper->localize( $entity->getCategory()->getName() - ). - ''. - ' > '. - ''. + ) . + '' . + ' > ' . + '' . $this->translatableStringHelper->localize( $entity->getName() - ). - ''. - $this->getDefaultClosingBox() - ; + ) . + '' . + $this->getDefaultClosingBox(); } /** - * * @param ActivityReason $entity - * @param array $options - * @return string */ public function renderString($entity, array $options): string { $category = ''; - + if (null !== $entity->getCategory()) { $category = $this->translatableStringHelper->localize( - $entity->getCategory()->getName()). ' > '; + $entity->getCategory()->getName() + ) . ' > '; } - + return $category . $this->translatableStringHelper->localize( $entity->getName() diff --git a/src/Bundle/ChillActivityBundle/Test/PrepareActivityTrait.php b/src/Bundle/ChillActivityBundle/Test/PrepareActivityTrait.php index ea78e8a67..2942b7948 100644 --- a/src/Bundle/ChillActivityBundle/Test/PrepareActivityTrait.php +++ b/src/Bundle/ChillActivityBundle/Test/PrepareActivityTrait.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Test; @@ -24,26 +14,19 @@ use Chill\MainBundle\Entity\Scope; use Chill\PersonBundle\Entity\Person; /** - * Prepare entities useful in tests - * - * - * @author Julien Fastré + * Prepare entities useful in tests. */ trait PrepareActivityTrait { /** - * Return an activity with a scope and a person inside - * - * @param Scope $scope - * @param Person $person + * Return an activity with a scope and a person inside. + * * @return Activity */ public function prepareActivity(Scope $scope, Person $person) { return (new Activity()) ->setScope($scope) - ->setPerson($person) - ; + ->setPerson($person); } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php index f1e6ecacd..493fac584 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityControllerTest.php @@ -1,16 +1,78 @@ getPersonFromFixtures(); + $activities = $this->getActivitiesForPerson($person); + + $user = $this->createFakeUser(); + + return [ + [ + $this->getAuthenticatedClient('center b_social'), + sprintf('fr/person/%d/activity/', $person->getId()), + ], + [ + $this->getAuthenticatedClient('center b_social'), + sprintf('fr/person/%d/activity/new', $person->getId()), + ], + [ + $this->getAuthenticatedClient('center b_social'), + sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()), + ], + [ + $this->getAuthenticatedClient('center b_social'), + sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()), + ], + [ + $this->getAuthenticatedClient($user->getUsername()), + sprintf('fr/person/%d/activity/new', $person->getId()), + ], + ]; + } + + /** + * Provide a client unauthenticated and. + */ + public function getSecuredPagesUnauthenticated() + { + static::bootKernel(); + $person = $this->getPersonFromFixtures(); + $activities = $this->getActivitiesForPerson($person); + + return [ + [sprintf('fr/person/%d/activity/', $person->getId())], + [sprintf('fr/person/%d/activity/new', $person->getId())], + [sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId())], + [sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId())], + ]; + } /** * @dataProvider getSecuredPagesUnauthenticated + * + * @param mixed $url */ public function testAccessIsDeniedForUnauthenticated($url) { @@ -19,13 +81,15 @@ class ActivityControllerTest extends WebTestCase $client->request('GET', $url); $this->assertEquals(302, $client->getResponse()->getStatusCode()); - $this->assertTrue($client->getResponse()->isRedirect('http://localhost/login'), - sprintf('the page "%s" does not redirect to http://localhost/login', $url)); + $this->assertTrue( + $client->getResponse()->isRedirect('http://localhost/login'), + sprintf('the page "%s" does not redirect to http://localhost/login', $url) + ); } /** - * * @dataProvider getSecuredPagesAuthenticated + * * @param type $client * @param type $url */ @@ -36,63 +100,6 @@ class ActivityControllerTest extends WebTestCase $this->assertEquals(403, $client->getResponse()->getStatusCode()); } - public function getSecuredPagesAuthenticated() - { - static::bootKernel(); - - $person = $this->getPersonFromFixtures(); - $activities = $this->getActivitiesForPerson($person); - - - $user = $this->createFakeUser(); - - - - return array( - array( - $this->getAuthenticatedClient('center b_social'), - sprintf('fr/person/%d/activity/', $person->getId()) - ), - array( - $this->getAuthenticatedClient('center b_social'), - sprintf('fr/person/%d/activity/new', $person->getId()) - ), - array( - $this->getAuthenticatedClient('center b_social'), - sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()) - ), - array( - $this->getAuthenticatedClient('center b_social'), - sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()) - ), - array( - $this->getAuthenticatedClient($user->getUsername()), - sprintf('fr/person/%d/activity/new', $person->getId()) - ) - ); - } - - - - /** - * Provide a client unauthenticated and - * - */ - public function getSecuredPagesUnauthenticated() - { - static::bootKernel(); - $person = $this->getPersonFromFixtures(); - $activities = $this->getActivitiesForPerson($person); - - return array( - [ sprintf('fr/person/%d/activity/', $person->getId()) ], - [ sprintf('fr/person/%d/activity/new', $person->getId()) ], - [ sprintf('fr/person/%d/activity/%d/show', $person->getId(), $activities[0]->getId()) ], - [ sprintf('fr/person/%d/activity/%d/edit', $person->getId(), $activities[0]->getId()) ], - ); - } - - public function testCompleteScenario() { // Create a new client to browse the application @@ -100,27 +107,32 @@ class ActivityControllerTest extends WebTestCase $person = $this->getPersonFromFixtures(); // Create a new entry in the database - $crawler = $client->request('GET', sprintf('en/person/%d/activity/', - $person->getId())); - $this->assertEquals(200, $client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /activity/"); + $crawler = $client->request('GET', sprintf( + 'en/person/%d/activity/', + $person->getId() + )); + $this->assertEquals( + 200, + $client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /activity/' + ); $crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité') - ->link()); + ->link()); $reason1 = $this->getRandomActivityReason(); - $reason2 = $this->getRandomActivityReason(array($reason1->getId())); + $reason2 = $this->getRandomActivityReason([$reason1->getId()]); // Fill in the form and submit it - $form = $crawler->selectButton('Ajouter une nouvelle activité')->form(array( - 'chill_activitybundle_activity'=> array( - 'date' => '15-01-2015', - 'durationTime' => 600, - // 'remark' => 'blabla', - 'scope' => $this->getRandomScope('center a_social', 'Center A')->getId(), - 'type' => $this->getRandomActivityType()->getId() - ) - )); - $form['chill_activitybundle_activity[reasons]']->select(array ($reason1->getId(), $reason2->getId())); + $form = $crawler->selectButton('Ajouter une nouvelle activité')->form([ + 'chill_activitybundle_activity' => [ + 'date' => '15-01-2015', + 'durationTime' => 600, + // 'remark' => 'blabla', + 'scope' => $this->getRandomScope('center a_social', 'Center A')->getId(), + 'type' => $this->getRandomActivityType()->getId(), + ], + ]); + $form['chill_activitybundle_activity[reasons]']->select([$reason1->getId(), $reason2->getId()]); $client->submit($form); @@ -128,18 +140,21 @@ class ActivityControllerTest extends WebTestCase $crawler = $client->followRedirect(); // Check data in the show view - $this->assertGreaterThan(0, $crawler->filter('dd:contains("January 15, 2015")')->count(), - 'Missing element dd:contains("January 15, 2015")'); + $this->assertGreaterThan( + 0, + $crawler->filter('dd:contains("January 15, 2015")')->count(), + 'Missing element dd:contains("January 15, 2015")' + ); // Edit the entity $crawler = $client->click($crawler->selectLink("Modifier l'activité")->link()); - $form = $crawler->selectButton("Sauver l'activité")->form(array( - 'chill_activitybundle_activity' => array( - 'date' => '25-01-2015', - // 'remark' => 'Foo' - ) - )); + $form = $crawler->selectButton("Sauver l'activité")->form([ + 'chill_activitybundle_activity' => [ + 'date' => '25-01-2015', + // 'remark' => 'Foo' + ], + ]); $client->submit($form); @@ -148,164 +163,33 @@ class ActivityControllerTest extends WebTestCase $crawler = $client->followRedirect(); // check that new data are present - $this->assertGreaterThan(0, - $crawler->filter('dd:contains("January 25, 2015")')->count(), - 'Missing element dd:contains("January 25, 2015")'); - $this->assertGreaterThan(0, - $crawler->filter('dd:contains("Foo")')->count(), - 'Missing element dd:contains("Foo")'); + $this->assertGreaterThan( + 0, + $crawler->filter('dd:contains("January 25, 2015")')->count(), + 'Missing element dd:contains("January 25, 2015")' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('dd:contains("Foo")')->count(), + 'Missing element dd:contains("Foo")' + ); // delete the actvity - $crawler = $client->click($crawler->selectLink("Supprimer")->link()); + $crawler = $client->click($crawler->selectLink('Supprimer')->link()); - $button = $crawler->selectButton('Supprimer'); + $button = $crawler->selectButton('Supprimer'); - $form = $button->form(); + $form = $button->form(); - $client->submit($form); - $this->assertTrue($client->getResponse()->isRedirect(sprintf('/en/person/%d/activity/', - $person->getId()))); + $client->submit($form); + $this->assertTrue($client->getResponse()->isRedirect(sprintf( + '/en/person/%d/activity/', + $person->getId() + ))); - $crawler = $client->followRedirect(); + $crawler = $client->followRedirect(); - $this->assertNotContains('January 25, 2015', $crawler->text()); - - } - - /** - * - * @return \Symfony\Component\BrowserKit\Client - */ - private function getAuthenticatedClient($username = 'center a_social') - { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => 'password', - )); - } - - /** - * - * @return \Chill\PersonBundle\Entity\Person - */ - private function getPersonFromFixtures() - { - $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - - $person = $em->getRepository('ChillPersonBundle:Person') - ->findOneBy(array( - 'firstName' => 'Depardieu', - 'lastName' => 'Gérard' - )); - - if ($person === NULL) { - throw new \RuntimeException("We need a person with firstname Gérard and" - . " lastname Depardieu. Did you add fixtures ?"); - } - - return $person; - } - - private function getActivitiesForPerson(\Chill\PersonBundle\Entity\Person $person) - { - $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - - $activities = $em->getRepository('ChillActivityBundle:Activity') - ->findBy(array('person' => $person)); - - if (count($activities) === 0) { - throw new \RuntimeException("We need activities associated with this " - . "person. Did you forget to add fixtures ?"); - } - - return $activities; - } - - /** - * - * @param string $username - * @param string $centerName - * @return \Chill\MainBundle\Entity\Scope - */ - private function getRandomScope($username, $centerName) - { - $user = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneByUsername($username); - - if ($user === NULL) { - throw new \RuntimeException("The user with username $username " - . "does not exists in database. Did you add fixtures ?"); - } - - $center = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:Center') - ->findOneByName($centerName); - - // get scope reachable by both role UPDATE and DELETE - $reachableScopesUpdate = static::$kernel->getContainer() - ->get('chill.main.security.authorization.helper') - ->getReachableScopes($user, new Role('CHILL_ACTIVITY_UPDATE'), - $center); - $reachableScopesDelete = static::$kernel->getContainer() - ->get('chill.main.security.authorization.helper') - ->getReachableScopes($user, new Role('CHILL_ACTIVITY_DELETE'), - $center); - $reachableScopesId = array_intersect( - array_map(function ($s) { return $s->getId(); }, $reachableScopesDelete), - array_map(function ($s) { return $s->getId(); }, $reachableScopesUpdate) - ); - if (count($reachableScopesId) === 0) { - throw new \RuntimeException("there are not scope reachable for " - . "both CHILL_ACTIVITY_UPDATE and CHILL_ACTIVITY_DELETE"); - } - - foreach($reachableScopesUpdate as $scope) { - if (in_array($scope->getId(), $reachableScopesId)) { - $reachableScopes[] = $scope; - } - } - - return $reachableScopes[array_rand($reachableScopes)]; - } - - /** - * - * @param int[] $excludeIds An array of id to exclude - * @return \Chill\ActivityBundle\Entity\ActivityReason - */ - private function getRandomActivityReason(array $excludeIds = array()) - { - $reasons = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillActivityBundle:ActivityReason') - ->findAll(); - - $reason = $reasons[array_rand($reasons)]; - - if (in_array($reason->getId(), $excludeIds)) { - return $this->getRandomActivityReason($excludeIds); - } - - return $reason; - } - - /** - * - * @return \Chill\ActivityBundle\Entity\ActivityType - */ - private function getRandomActivityType() - { - $types = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillActivityBundle:ActivityType') - ->findAll(); - - return $types[array_rand($types)]; + $this->assertNotContains('January 25, 2015', $crawler->text()); } /** @@ -321,10 +205,10 @@ class ActivityControllerTest extends WebTestCase //get the social PermissionGroup, and remove CHILL_ACTIVITY_* $socialPermissionGroup = $em - ->getRepository('ChillMainBundle:PermissionsGroup') - ->findOneByName('social'); + ->getRepository('ChillMainBundle:PermissionsGroup') + ->findOneByName('social'); $withoutActivityPermissionGroup = (new \Chill\MainBundle\Entity\PermissionsGroup()) - ->setName('social without activity'); + ->setName('social without activity'); //copy role scopes where ACTIVITY is not present foreach ($socialPermissionGroup->getRoleScopes() as $roleScope) { if (!strpos($roleScope->getRole(), 'ACTIVITY')) { @@ -334,8 +218,8 @@ class ActivityControllerTest extends WebTestCase //create groupCenter $groupCenter = new \Chill\MainBundle\Entity\GroupCenter(); $groupCenter->setCenter($em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A'))) - ->setPermissionsGroup($withoutActivityPermissionGroup); + ->findOneBy(['name' => 'Center A'])) + ->setPermissionsGroup($withoutActivityPermissionGroup); $em->persist($withoutActivityPermissionGroup); $em->persist($groupCenter); @@ -344,10 +228,10 @@ class ActivityControllerTest extends WebTestCase $username = $faker->name; $user = new \Chill\MainBundle\Entity\User(); $user - ->setPassword($container->get('security.password_encoder') - ->encodePassword($user, 'password')) - ->setUsername($username) - ->addGroupCenter($groupCenter); + ->setPassword($container->get('security.password_encoder') + ->encodePassword($user, 'password')) + ->setUsername($username) + ->addGroupCenter($groupCenter); $em->persist($user); @@ -355,4 +239,146 @@ class ActivityControllerTest extends WebTestCase return $user; } + + private function getActivitiesForPerson(\Chill\PersonBundle\Entity\Person $person) + { + $em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + $activities = $em->getRepository('ChillActivityBundle:Activity') + ->findBy(['person' => $person]); + + if (count($activities) === 0) { + throw new RuntimeException('We need activities associated with this ' + . 'person. Did you forget to add fixtures ?'); + } + + return $activities; + } + + /** + * @param mixed $username + * + * @return \Symfony\Component\BrowserKit\Client + */ + private function getAuthenticatedClient($username = 'center a_social') + { + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => 'password', + ]); + } + + /** + * @return \Chill\PersonBundle\Entity\Person + */ + private function getPersonFromFixtures() + { + $em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + $person = $em->getRepository('ChillPersonBundle:Person') + ->findOneBy([ + 'firstName' => 'Depardieu', + 'lastName' => 'Gérard', + ]); + + if (null === $person) { + throw new RuntimeException('We need a person with firstname Gérard and' + . ' lastname Depardieu. Did you add fixtures ?'); + } + + return $person; + } + + /** + * @param int[] $excludeIds An array of id to exclude + * + * @return \Chill\ActivityBundle\Entity\ActivityReason + */ + private function getRandomActivityReason(array $excludeIds = []) + { + $reasons = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillActivityBundle:ActivityReason') + ->findAll(); + + $reason = $reasons[array_rand($reasons)]; + + if (in_array($reason->getId(), $excludeIds)) { + return $this->getRandomActivityReason($excludeIds); + } + + return $reason; + } + + /** + * @return \Chill\ActivityBundle\Entity\ActivityType + */ + private function getRandomActivityType() + { + $types = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillActivityBundle:ActivityType') + ->findAll(); + + return $types[array_rand($types)]; + } + + /** + * @param string $username + * @param string $centerName + * + * @return \Chill\MainBundle\Entity\Scope + */ + private function getRandomScope($username, $centerName) + { + $user = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:User') + ->findOneByUsername($username); + + if (null === $user) { + throw new RuntimeException("The user with username {$username} " + . 'does not exists in database. Did you add fixtures ?'); + } + + $center = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:Center') + ->findOneByName($centerName); + + // get scope reachable by both role UPDATE and DELETE + $reachableScopesUpdate = static::$kernel->getContainer() + ->get('chill.main.security.authorization.helper') + ->getReachableScopes( + $user, + new Role('CHILL_ACTIVITY_UPDATE'), + $center + ); + $reachableScopesDelete = static::$kernel->getContainer() + ->get('chill.main.security.authorization.helper') + ->getReachableScopes( + $user, + new Role('CHILL_ACTIVITY_DELETE'), + $center + ); + $reachableScopesId = array_intersect( + array_map(function ($s) { return $s->getId(); }, $reachableScopesDelete), + array_map(function ($s) { return $s->getId(); }, $reachableScopesUpdate) + ); + + if (count($reachableScopesId) === 0) { + throw new RuntimeException('there are not scope reachable for ' + . 'both CHILL_ACTIVITY_UPDATE and CHILL_ACTIVITY_DELETE'); + } + + foreach ($reachableScopesUpdate as $scope) { + if (in_array($scope->getId(), $reachableScopesId)) { + $reachableScopes[] = $scope; + } + } + + return $reachableScopes[array_rand($reachableScopes)]; + } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonCategoryControllerTest.php b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonCategoryControllerTest.php index 9222d4b39..dde5ed304 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonCategoryControllerTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonCategoryControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class ActivityReasonCategoryControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonControllerTest.php b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonControllerTest.php index 5ee8cf977..88a41206b 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonControllerTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityReasonControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class ActivityReasonControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityTypeControllerTest.php b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityTypeControllerTest.php index 9249f14ae..42b2106a1 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityTypeControllerTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Controller/ActivityTypeControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class ActivityTypeControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityReasonAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityReasonAggregatorTest.php index a79ee50d3..d0a164cd2 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityReasonAggregatorTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityReasonAggregatorTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Aggregator; @@ -22,59 +12,59 @@ namespace Chill\ActivityBundle\Tests\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; /** - * Add tests for ActivityReasonAggregator + * Add tests for ActivityReasonAggregator. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ActivityReasonAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.activity.export.reason_aggregator'); - + + $this->aggregator = $container->get('chill.activity.export.reason_aggregator'); + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array('level' => 'reasons'), - array('level' => 'categories') - ); + return [ + ['level' => 'reasons'], + ['level' => 'categories'], + ]; } - + public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity'), @@ -86,8 +76,7 @@ class ActivityReasonAggregatorTest extends AbstractAggregatorTest ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.reasons', 'reasons') - ->join('reasons.category', 'category') - ); + ->join('reasons.category', 'category'), + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityTypeAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityTypeAggregatorTest.php index d3e4efd84..a1803809d 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityTypeAggregatorTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityTypeAggregatorTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Aggregator; @@ -22,58 +12,58 @@ namespace Chill\ActivityBundle\Tests\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; /** - * Add tests for ActivityTypeAggregator + * Add tests for ActivityTypeAggregator. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ActivityTypeAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\ActivityBundle\Export\Aggregator\ActivityReasonAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.activity.export.type_aggregator'); - + + $this->aggregator = $container->get('chill.activity.export.type_aggregator'); + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } - + public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity'), @@ -85,8 +75,7 @@ class ActivityTypeAggregatorTest extends AbstractAggregatorTest ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.reasons', 'reasons') - ->join('reasons.category', 'category') - ); + ->join('reasons.category', 'category'), + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityUserAggregatorTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityUserAggregatorTest.php index 45f974a56..c47df37a9 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityUserAggregatorTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Aggregator/ActivityUserAggregatorTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Aggregator; @@ -22,57 +12,58 @@ namespace Chill\ActivityBundle\Tests\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; /** - * Add tests for ActivityUsernAggregator + * Add tests for ActivityUsernAggregator. * + * @internal + * @coversNothing */ class ActivityUserAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\ActivityBundle\Export\Aggregator\ActivityUserAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.activity.export.user_aggregator'); - + + $this->aggregator = $container->get('chill.activity.export.user_aggregator'); + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } - + public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity'), @@ -84,8 +75,7 @@ class ActivityUserAggregatorTest extends AbstractAggregatorTest ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.reasons', 'reasons') - ->join('reasons.category', 'category') - ); + ->join('reasons.category', 'category'), + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/CountActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/CountActivityTest.php index 4f9918fd0..00bb1b945 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/CountActivityTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/CountActivityTest.php @@ -1,32 +1,37 @@ + * @internal + * @coversNothing */ class CountActivityTest extends AbstractExportTest { /** - * - * @var + * @var */ private $export; - + public function setUp() { static::bootKernel(); - + /* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ $container = self::$kernel->getContainer(); - + $this->export = $container->get('chill.activity.export.count_activity'); } - + public function getExport() { return $this->export; @@ -34,17 +39,16 @@ class CountActivityTest extends AbstractExportTest public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } public function getModifiersCombination() { - return array( - array('activity'), - array('activity', 'person') - ); + return [ + ['activity'], + ['activity', 'person'], + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/ListActivityTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/ListActivityTest.php index dbb660e55..bcc9fb034 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/ListActivityTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/ListActivityTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Export\Export; @@ -22,67 +12,33 @@ namespace Chill\ActivityBundle\Tests\Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class ListActivityTest extends AbstractExportTest { /** - * * @var \Chill\ActivityBundle\Export\Export\ListActivity */ private $export; - + public function setUp() { static::bootKernel(); - + /* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ $container = self::$kernel->getContainer(); - + $this->export = $container->get('chill.activity.export.list_activity'); - + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); - } - - - - public function getFormData() - { - return array( - array('fields' => array( - 'id', - 'date', - 'durationTime', - 'attendee', - 'user_username', - 'circle_name', - 'type_name', - 'person_firstname', - 'person_lastname', - 'person_id' - )), - array('fields' => array( - 'id', - 'list_reasons' - )), - ); - } - - public function getModifiersCombination() - { - return array( - array('activity'), - array('activity', 'person') - ); + ->push($request->reveal()); } public function getExport() @@ -90,4 +46,33 @@ class ListActivityTest extends AbstractExportTest return $this->export; } + public function getFormData() + { + return [ + ['fields' => [ + 'id', + 'date', + 'durationTime', + 'attendee', + 'user_username', + 'circle_name', + 'type_name', + 'person_firstname', + 'person_lastname', + 'person_id', + ]], + ['fields' => [ + 'id', + 'list_reasons', + ]], + ]; + } + + public function getModifiersCombination() + { + return [ + ['activity'], + ['activity', 'person'], + ]; + } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Export/StatActivityDurationSumTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Export/StatActivityDurationSumTest.php index f43374fd8..963ecbaaa 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Export/StatActivityDurationSumTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Export/StatActivityDurationSumTest.php @@ -1,32 +1,39 @@ + * @internal + * @coversNothing */ class StatActivityDurationSumTest extends AbstractExportTest { /** - * * @var \Chill\ActivityBundle\Export\Export\StatActivityDuration */ private $export; - + public function setUp() { static::bootKernel(); - + /* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ $container = self::$kernel->getContainer(); - + $this->export = $container->get('chill.activity.export.sum_activity_duration'); } - + public function getExport() { return $this->export; @@ -34,17 +41,16 @@ class StatActivityDurationSumTest extends AbstractExportTest public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } public function getModifiersCombination() { - return array( - array('activity'), - array('activity', 'person') - ); + return [ + ['activity'], + ['activity', 'person'], + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityReasonFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityReasonFilterTest.php index 1c4ca4c21..13f2ae2c4 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityReasonFilterTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/ActivityReasonFilterTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Filter; @@ -23,37 +13,34 @@ use Chill\MainBundle\Test\Export\AbstractFilterTest; use Doctrine\Common\Collections\ArrayCollection; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class ActivityReasonFilterTest extends AbstractFilterTest { /** - * * @var \Chill\PersonBundle\Export\Filter\GenderFilter */ private $filter; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - + $this->filter = $container->get('chill.activity.export.reason_filter'); - + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - - + public function getFilter() { return $this->filter; @@ -61,36 +48,35 @@ class ActivityReasonFilterTest extends AbstractFilterTest public function getFormData() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ; - - $reasons = $em->createQuery("SELECT reason " - . "FROM ChillActivityBundle:ActivityReason reason") - ->getResult(); - + ->get('doctrine.orm.entity_manager'); + + $reasons = $em->createQuery('SELECT reason ' + . 'FROM ChillActivityBundle:ActivityReason reason') + ->getResult(); + // generate an array of 5 different combination of results - for ($i=0; $i < 5; $i++) { - $r[] = array('reasons' => new ArrayCollection(array_splice($reasons, ($i + 1) * -1))); + for ($i = 0; 5 > $i; ++$i) { + $r[] = ['reasons' => new ArrayCollection(array_splice($reasons, ($i + 1) * -1))]; } - + return $r; } public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity'), @@ -102,8 +88,7 @@ class ActivityReasonFilterTest extends AbstractFilterTest ->select('count(activity.id)') ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.reasons', 'reasons') - ->join('reasons.category', 'category') - ); + ->join('reasons.category', 'category'), + ]; } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonHavingActivityBetweenDateFilterTest.php b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonHavingActivityBetweenDateFilterTest.php index 5b922e6f3..a20b5d3e1 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonHavingActivityBetweenDateFilterTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Export/Filter/PersonHavingActivityBetweenDateFilterTest.php @@ -1,56 +1,47 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\ActivityBundle\Tests\Filter; use Chill\MainBundle\Test\Export\AbstractFilterTest; +use DateTime; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest { /** - * * @var \Chill\PersonBundle\Export\Filter\PersonHavingActivityBetweenDateFilter */ private $filter; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - + $this->filter = $container->get('chill.activity.export.' . 'person_having_an_activity_between_date_filter'); - + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - + public function getFilter() { return $this->filter; @@ -58,49 +49,33 @@ class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest public function getFormData() { - $date_from = \DateTime::createFromFormat('Y-m-d', '2015-01-15'); - $date_to = new \DateTime(); // today + $date_from = DateTime::createFromFormat('Y-m-d', '2015-01-15'); + $date_to = new DateTime(); // today $reasons = $this->getActivityReasons(); - - $data = array(); - for ($i = 0; $i < 4; $i++) { - $data[] = array( + $data = []; + + for ($i = 0; 4 > $i; ++$i) { + $data[] = [ 'date_from' => $date_from, - 'date_to' => $date_to, - 'reasons' => array_slice($reasons, 0, 1 + $i) - ); + 'date_to' => $date_to, + 'reasons' => array_slice($reasons, 0, 1 + $i), + ]; } - + return $data; } - - /** - * Return all activity reasons - * - * @return \Chill\ActivityBundle\Entity\ActivityReason[] - */ - private function getActivityReasons() - { - if (static::$kernel === null) { - static::bootKernel(); - } - - return static::$kernel->getContainer() - ->get('chill_activity.repository.reason') - ->findAll(); - } public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(person.id)') ->from('ChillPersonBundle:Person', 'person') @@ -112,6 +87,22 @@ class PersonHavingActivityBetweenDateFilterTest extends AbstractFilterTest ->join('activity.person', 'person') // add a fake where clause ->where('person.id > 0'), - ); + ]; + } + + /** + * Return all activity reasons. + * + * @return \Chill\ActivityBundle\Entity\ActivityReason[] + */ + private function getActivityReasons() + { + if (null === static::$kernel) { + static::bootKernel(); + } + + return static::$kernel->getContainer() + ->get('chill_activity.repository.reason') + ->findAll(); } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php b/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php index 07e48cb56..a00ccdbf7 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Form/ActivityTypeTest.php @@ -1,183 +1,170 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Form; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\ActivityBundle\Form\ActivityType; use Chill\ActivityBundle\Entity\Activity; +use Chill\ActivityBundle\Form\ActivityType; +use DateTime; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Form\Extension\Core\Type\FormType; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class ActivityTypeTest extends KernelTestCase { /** - * - * @var \Symfony\Component\Form\FormBuilderInterface + * @var \Chill\MainBundle\Entity\Center */ - protected $formBuilder; + protected $center; /** - * * @var \Symfony\Component\DependencyInjection\ContainerInterface */ protected $container; /** - * + * @var \Symfony\Component\Form\FormBuilderInterface + */ + protected $formBuilder; + + /** * @var \Symfony\Component\Security\Core\User\UserInterface */ protected $user; - /** - * - * @var \Chill\MainBundle\Entity\Center - */ - protected $center; - public function setUp() { self::bootKernel(); $this->container = self::$kernel->getContainer(); - $prophet = new \Prophecy\Prophet; - + $prophet = new \Prophecy\Prophet(); $this->formBuilder = $this->container - ->get('form.factory') - ->createBuilder(FormType::class, null, array( - 'csrf_protection' => false, - 'csrf_field_name' => '_token' - )); + ->get('form.factory') + ->createBuilder(FormType::class, null, [ + 'csrf_protection' => false, + 'csrf_field_name' => '_token', + ]); $request = new \Symfony\Component\HttpFoundation\Request(); $request->setLocale('fr'); self::$kernel->getContainer() - ->get('request_stack') - ->push($request); + ->get('request_stack') + ->push($request); $this->user = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => 'center a_social')); + ->getRepository('ChillMainBundle:User') + ->findOneBy(['username' => 'center a_social']); $this->center = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); + ->getRepository('ChillMainBundle:Center') + ->findOneBy(['name' => 'Center A']); $token = $prophet->prophesize(); $token->willExtend(AbstractToken::class); $token->getUser()->willReturn($this->user); $this->container->get('security.token_storage') - ->setToken($token->reveal()); - + ->setToken($token->reveal()); } public function testForm() { $form = $this->formBuilder - ->add('activity', ActivityType::class, array( - 'center' => $this->center, - 'role' => new Role('CHILL_ACTIVITY_CREATE') - )) - ->getForm(); + ->add('activity', ActivityType::class, [ + 'center' => $this->center, + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + ]) + ->getForm(); - $form->submit(array()); + $form->submit([]); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form->isValid()); $this->assertInstanceOf(Activity::class, $form->getData()['activity']); - } public function testFormSubmitting() { $form = $this->formBuilder - ->add('activity', ActivityType::class, array( - 'center' => $this->center, - 'role' => new Role('CHILL_ACTIVITY_CREATE') - )) - ->getForm(); + ->add('activity', ActivityType::class, [ + 'center' => $this->center, + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + ]) + ->getForm(); - $form->submit(array( 'activity' => array( + $form->submit(['activity' => [ 'date' => '9-3-2015', 'durationTime' => 300, - // 'remark' => 'blabla', - 'attendee' => true - ))); + // 'remark' => 'blabla', + 'attendee' => true, + ]]); // var_dump($form->getErrors()->count()); var_dump($form->isValid()); // foreach($form->getErrors() as $e) { fwrite(STDOUT, var_dump($e->getMessage())); } // var_dump($form->getErrors()); - $this->assertTrue($form->isSynchronized(), "Test the form is synchronized"); - $this->assertTrue($form->isValid(), "test the form is valid"); + $this->assertTrue($form->isSynchronized(), 'Test the form is synchronized'); + $this->assertTrue($form->isValid(), 'test the form is valid'); $this->assertInstanceOf(Activity::class, $form->getData()['activity']); // test the activity /* @var $activity Activity */ $activity = $form->getData()['activity']; - $this->assertEquals('09-03-2015', $activity->getDate()->format('d-m-Y'), - "Test the date is correct"); - $this->assertEquals('00:05', $activity->getDurationTime()->format('H:i'), - "Test the formatted hour is correct"); + $this->assertEquals( + '09-03-2015', + $activity->getDate()->format('d-m-Y'), + 'Test the date is correct' + ); + $this->assertEquals( + '00:05', + $activity->getDurationTime()->format('H:i'), + 'Test the formatted hour is correct' + ); $this->assertEquals(true, $activity->getAttendee()); - // $this->assertEquals('blabla', $activity->getRemark()); - + // $this->assertEquals('blabla', $activity->getRemark()); } /** * Test that the form correctly build even with a durationTime which is not in - * the listed in the possible durationTime + * the listed in the possible durationTime. */ public function testFormWithActivityHavingDifferentTime() { $activity = new Activity(); - $activity->setDurationTime(\DateTime::createFromFormat('U', 60)); + $activity->setDurationTime(DateTime::createFromFormat('U', 60)); $builder = $this->container - ->get('form.factory') - ->createBuilder(FormType::class, array('activity' => $activity), array( - 'csrf_protection' => false, - 'csrf_field_name' => '_token' - )); + ->get('form.factory') + ->createBuilder(FormType::class, ['activity' => $activity], [ + 'csrf_protection' => false, + 'csrf_field_name' => '_token', + ]); $form = $builder - ->add('activity', ActivityType::class, array( - 'center' => $this->center, - 'role' => new Role('CHILL_ACTIVITY_CREATE') - )) - ->getForm(); + ->add('activity', ActivityType::class, [ + 'center' => $this->center, + 'role' => new Role('CHILL_ACTIVITY_CREATE'), + ]) + ->getForm(); - - $form->submit(array( 'activity' => array( + $form->submit(['activity' => [ 'date' => '9-3-2015', 'durationTime' => 60, - // 'remark' => 'blabla', - 'attendee' => true - ))); + // 'remark' => 'blabla', + 'attendee' => true, + ]]); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form->isValid()); @@ -186,8 +173,11 @@ class ActivityTypeTest extends KernelTestCase /* @var $activity Activity */ $activity = $form->getData()['activity']; - $this->assertEquals('00:01', $activity->getDurationTime()->format('H:i'), - "Test the formatted hour is correct"); + $this->assertEquals( + '00:01', + $activity->getDurationTime()->format('H:i'), + 'Test the formatted hour is correct' + ); // test the view : we want to be sure that the entry with 60 seconds exists $view = $form->createView(); @@ -195,11 +185,11 @@ class ActivityTypeTest extends KernelTestCase $this->assertTrue(isset($view['activity']['durationTime'])); // map all the values in an array - $values = array_map(function($choice) { return $choice->value; }, - $view['activity']['durationTime']->vars['choices']); + $values = array_map( + function ($choice) { return $choice->value; }, + $view['activity']['durationTime']->vars['choices'] + ); $this->assertContains(60, $values); - } - } diff --git a/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityReasonTest.php b/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityReasonTest.php index 59812009e..5c7ace286 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityReasonTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityReasonTest.php @@ -1,110 +1,96 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Form\Type; -use Symfony\Component\Form\Test\TypeTestCase; use Chill\ActivityBundle\Form\Type\TranslatableActivityReason; use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Form\PreloadedExtension; +use Symfony\Component\Form\Test\TypeTestCase; /** - * Test translatableActivityReason + * Test translatableActivityReason. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class TranslatableActivityReasonTest extends TypeTestCase { /** - * - * @var Prophecy\Prophet + * @var Prophecy\Prophet */ private static $prophet; - + public function setUp() { parent::setUp(); - - } - - protected function getExtensions() - { - $entityType = $this->getEntityType(); - - return array(new PreloadedExtension(array( - 'entity' => $entityType - ), array())); - } - - + public function testSimple() { $translatableActivityReasonType = new TranslatableActivityReason( - $this->getTranslatableStringHelper() - ); - - $this->markTestSkipped("See issue 651"); + $this->getTranslatableStringHelper() + ); + + $this->markTestSkipped('See issue 651'); } - + /** - * - * @param string $locale - * @param string $fallbackLocale - * @return TranslatableStringHelper - */ - protected function getTranslatableStringHelper($locale = 'en', - $fallbackLocale = 'en') - { - $prophet = new \Prophecy\Prophet; - $requestStack = $prophet->prophesize(); - $request = $prophet->prophesize(); - $translator = $prophet->prophesize(); - - $request->willExtend('Symfony\Component\HttpFoundation\Request'); - $request->getLocale()->willReturn($fallbackLocale); - - $requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack'); - $requestStack->getCurrentRequest()->will(function () use ($request) { - return $request; - }); - - $translator->willExtend('Symfony\Component\Translation\Translator'); - $translator->getFallbackLocales()->willReturn($locale); - - return new TranslatableStringHelper($requestStack->reveal(), - $translator->reveal()); - - } - - /** - * * @return \Symfony\Bridge\Doctrine\Form\Type\EntityType */ protected function getEntityType() { $managerRegistry = (new \Prophecy\Prophet())->prophesize(); - + $managerRegistry->willImplement('Doctrine\Common\Persistence\ManagerRegistry'); - + return new \Symfony\Bridge\Doctrine\Form\Type\EntityType($managerRegistry->reveal()); } + + protected function getExtensions() + { + $entityType = $this->getEntityType(); + + return [new PreloadedExtension([ + 'entity' => $entityType, + ], [])]; + } + + /** + * @param string $locale + * @param string $fallbackLocale + * + * @return TranslatableStringHelper + */ + protected function getTranslatableStringHelper( + $locale = 'en', + $fallbackLocale = 'en' + ) { + $prophet = new \Prophecy\Prophet(); + $requestStack = $prophet->prophesize(); + $request = $prophet->prophesize(); + $translator = $prophet->prophesize(); + + $request->willExtend('Symfony\Component\HttpFoundation\Request'); + $request->getLocale()->willReturn($fallbackLocale); + + $requestStack->willExtend('Symfony\Component\HttpFoundation\RequestStack'); + $requestStack->getCurrentRequest()->will(function () use ($request) { + return $request; + }); + + $translator->willExtend('Symfony\Component\Translation\Translator'); + $translator->getFallbackLocales()->willReturn($locale); + + return new TranslatableStringHelper( + $requestStack->reveal(), + $translator->reveal() + ); + } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityTypeTest.php b/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityTypeTest.php index b0f1e6e95..1e5a6714b 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityTypeTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Form/Type/TranslatableActivityTypeTest.php @@ -1,116 +1,101 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Form\Type; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Chill\ActivityBundle\Form\Type\TranslatableActivityType; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Form\Extension\Core\Type\FormType; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class TranslatableActivityTypeTest extends KernelTestCase { - /** - * * @var \Symfony\Component\Form\FormBuilderInterface */ protected $builder; - + /** - * * @var \Symfony\Component\DependencyInjection\ContainerInterface */ protected $container; - + public function setUp() { self::bootKernel(); - + $this->container = self::$kernel->getContainer(); - + $this->builder = $this->container - ->get('form.factory') - ->createBuilder(FormType::class, null, array( - 'csrf_protection' => false, - 'csrf_field_name' => '_token' - )); - + ->get('form.factory') + ->createBuilder(FormType::class, null, [ + 'csrf_protection' => false, + 'csrf_field_name' => '_token', + ]); + $request = new \Symfony\Component\HttpFoundation\Request(); $request->setLocale('fr'); - + $this->container->get('request_stack') - ->push($request); + ->push($request); } - - /** - * - * @return \Chill\ActivityBundle\Entity\ActivityType - */ - protected function getRandomType($active = true) - { - $types = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillActivityBundle:ActivityType') - ->findBy(array('active' => $active)); - - return $types[array_rand($types)]; - } - + public function testForm() { $type = $this->getRandomType(); $form = $this->builder->add('type', TranslatableActivityType::class) - ->getForm(); - - $form->submit(array( - 'type' => $type->getId() - )); - + ->getForm(); + + $form->submit([ + 'type' => $type->getId(), + ]); + $this->assertTrue($form->isSynchronized()); - $this->assertInstanceOf(\Chill\ActivityBundle\Entity\ActivityType::class, - $form->getData()['type'], - "The data is an instance of Chill\ActivityBundle\Entity\ActivityType"); + $this->assertInstanceOf( + \Chill\ActivityBundle\Entity\ActivityType::class, + $form->getData()['type'], + 'The data is an instance of Chill\\ActivityBundle\\Entity\\ActivityType' + ); $this->assertEquals($type->getId(), $form->getData()['type']->getId()); - + // test the ordering of the types in the form // since 2016-11-14 the types are not alphabetically ordered, skipping /*$view = $form->createView(); - + $this->assertGreaterThan(0, count($view['type']->vars['choices']), "test that there are at least one choice"); - + foreach($view['type']->vars['choices'] as $choice) { // initialize the previous value is not set (this is the first) - if (!isset($previous)) { - $previous = $choice->label; + if (!isset($previous)) { + $previous = $choice->label; } else { $this->assertTrue($previous < $choice->label); $previous = $choice->label; } }*/ - } - - - + + /** + * @param mixed $active + * + * @return \Chill\ActivityBundle\Entity\ActivityType + */ + protected function getRandomType($active = true) + { + $types = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillActivityBundle:ActivityType') + ->findBy(['active' => $active]); + + return $types[array_rand($types)]; + } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Security/Authorization/ActivityVoterTest.php b/src/Bundle/ChillActivityBundle/Tests/Security/Authorization/ActivityVoterTest.php index 2a9cd6fae..3c16197a8 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Security/Authorization/ActivityVoterTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Security/Authorization/ActivityVoterTest.php @@ -1,103 +1,55 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Security\Authorization; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Chill\ActivityBundle\Test\PrepareActivityTrait; use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Test\PrepareUserTrait; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Test\PrepareCenterTrait; use Chill\MainBundle\Test\PrepareScopeTrait; +use Chill\MainBundle\Test\PrepareUserTrait; use Chill\PersonBundle\Test\PreparePersonTrait; -use Chill\ActivityBundle\Test\PrepareActivityTrait; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class ActivityVoterTest extends KernelTestCase { - use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait, - PreparePersonTrait, PrepareActivityTrait; - + use PrepareActivityTrait; + use PrepareCenterTrait; + use PreparePersonTrait; + use PrepareScopeTrait; + use PrepareUserTrait; + /** - * - * @var \Chill\PersonBundle\Security\Authorization\PersonVoter - */ - protected $voter; - - /** - * * @var \Prophecy\Prophet */ protected $prophet; - + + /** + * @var \Chill\PersonBundle\Security\Authorization\PersonVoter + */ + protected $voter; + public function setUp() { static::bootKernel(); $this->voter = static::$kernel->getContainer() - ->get('chill.activity.security.authorization.activity_voter'); + ->get('chill.activity.security.authorization.activity_voter'); $this->prophet = new \Prophecy\Prophet(); } - - public function testNullUser() - { - $token = $this->prepareToken(); - $center = $this->prepareCenter(1, 'center'); - $person = $this->preparePerson($center); - $scope = $this->prepareScope(1, 'default'); - $activity = $this->prepareActivity($scope, $person); - - $this->assertEquals( - VoterInterface::ACCESS_DENIED, - $this->voter->vote($token, $activity, array('CHILL_ACTIVITY_SEE')), - "assert that a null user is not allowed to see" - ); - } - - /** - * - * @dataProvider dataProvider_testVoteAction - * @param type $expectedResult - * @param User $user - * @param Scope $scope - * @param Center $center - * @param string $attribute - * @param string $message - */ - public function testVoteAction($expectedResult, User $user, Scope $scope, - Center $center, $attribute, $message) - { - $token = $this->prepareToken($user); - $activity = $this->prepareActivity($scope, $this->preparePerson($center)); - - $this->assertEquals( - $expectedResult, - $this->voter->vote($token, $activity, array($attribute)), - $message - ); - } - + public function dataProvider_testVoteAction() { $centerA = $this->prepareCenter(1, 'center A'); @@ -105,72 +57,111 @@ class ActivityVoterTest extends KernelTestCase $scopeA = $this->prepareScope(1, 'scope default'); $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - - $userA = $this->prepareUser(array( - array( - 'center' => $centerA, - 'permissionsGroup' => array( + + $userA = $this->prepareUser([ + [ + 'center' => $centerA, + 'permissionsGroup' => [ ['scope' => $scopeB, 'role' => 'CHILL_ACTIVITY_CREATE'], - ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_SEE'] - ) - ), - array( - 'center' => $centerB, - 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_CREATE'], - ['scope' => $scopeC, 'role' => 'CHILL_ACTIVITY_CREATE'] - ) - ) - - )); - - return array( - array( + ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_SEE'], + ], + ], + [ + 'center' => $centerB, + 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_ACTIVITY_CREATE'], + ['scope' => $scopeC, 'role' => 'CHILL_ACTIVITY_CREATE'], + ], + ], + ]); + + return [ + [ VoterInterface::ACCESS_GRANTED, $userA, $scopeB, $centerA, 'CHILL_ACTIVITY_CREATE', - 'assert that a user granted with same rights' - ), - array( + 'assert that a user granted with same rights', + ], + [ VoterInterface::ACCESS_GRANTED, $userA, $scopeB, $centerA, 'CHILL_ACTIVITY_SEE', - 'assert that a user granted with inheritance rights' - ), - array( + 'assert that a user granted with inheritance rights', + ], + [ VoterInterface::ACCESS_DENIED, $userA, $scopeC, $centerA, 'CHILL_ACTIVITY_SEE', - 'assert that a suer is denied if he is not granted right on this center' - - ) + 'assert that a suer is denied if he is not granted right on this center', + ], + ]; + } + + public function testNullUser() + { + $token = $this->prepareToken(); + $center = $this->prepareCenter(1, 'center'); + $person = $this->preparePerson($center); + $scope = $this->prepareScope(1, 'default'); + $activity = $this->prepareActivity($scope, $person); + + $this->assertEquals( + VoterInterface::ACCESS_DENIED, + $this->voter->vote($token, $activity, ['CHILL_ACTIVITY_SEE']), + 'assert that a null user is not allowed to see' ); } - + /** - * prepare a token interface with correct rights - * + * @dataProvider dataProvider_testVoteAction + * + * @param type $expectedResult + * @param string $attribute + * @param string $message + */ + public function testVoteAction( + $expectedResult, + User $user, + Scope $scope, + Center $center, + $attribute, + $message + ) { + $token = $this->prepareToken($user); + $activity = $this->prepareActivity($scope, $this->preparePerson($center)); + + $this->assertEquals( + $expectedResult, + $this->voter->vote($token, $activity, [$attribute]), + $message + ); + } + + /** + * prepare a token interface with correct rights. + * * if $permissions = null, user will be null (no user associated with token - * + * * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface */ - protected function prepareToken(User $user = null) - { + protected function prepareToken(?User $user = null) + { $token = $this->prophet->prophesize(); $token ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - if ($user === NULL) { + + if (null === $user) { $token->getUser()->willReturn(null); } else { $token->getUser()->willReturn($user); } - + return $token->reveal(); } } diff --git a/src/Bundle/ChillActivityBundle/Tests/Timeline/TimelineProviderTest.php b/src/Bundle/ChillActivityBundle/Tests/Timeline/TimelineProviderTest.php index 7c25cc0d9..2179c5361 100644 --- a/src/Bundle/ChillActivityBundle/Tests/Timeline/TimelineProviderTest.php +++ b/src/Bundle/ChillActivityBundle/Tests/Timeline/TimelineProviderTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Tests\Timeline; @@ -22,15 +12,13 @@ namespace Chill\ActivityBundle\Tests\Timeline; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class TimelineProviderTest extends WebTestCase { public function testAnActivityIsShownOnTimeline() { - $this->markTestSkipped("we have to write fixtures before writing this tests"); + $this->markTestSkipped('we have to write fixtures before writing this tests'); } - } diff --git a/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php b/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php index c87a17af4..5ca887245 100644 --- a/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php +++ b/src/Bundle/ChillActivityBundle/Timeline/TimelineActivityProvider.php @@ -1,219 +1,198 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ActivityBundle\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Timeline\TimelineProviderInterface; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadata; +use LogicException; +use RuntimeException; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Mapping\ClassMetadata; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\Scope; /** - * Provide activity for inclusion in timeline - * - * @author Julien Fastré - * @author Champs Libres + * Provide activity for inclusion in timeline. */ class TimelineActivityProvider implements TimelineProviderInterface { - /** - * * @var EntityManager */ protected $em; - + /** - * * @var AuthorizationHelper */ protected $helper; - + /** - * - * @var \Chill\MainBundle\Entity\User + * @var \Chill\MainBundle\Entity\User */ protected $user; - + /** * TimelineActivityProvider constructor. - * - * @param EntityManager $em - * @param AuthorizationHelper $helper - * @param TokenStorageInterface $storage */ public function __construct( EntityManager $em, AuthorizationHelper $helper, TokenStorageInterface $storage - ) - { + ) { $this->em = $em; $this->helper = $helper; - - if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) - { - throw new \RuntimeException('A user should be authenticated !'); + + if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) { + throw new RuntimeException('A user should be authenticated !'); } - + $this->user = $storage->getToken()->getUser(); } - - /** - * - * {@inheritDoc} - */ + public function fetchQuery($context, array $args) { $this->checkContext($context); - + $metadataActivity = $this->em->getClassMetadata('ChillActivityBundle:Activity'); $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); - - return array( - 'id' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('id'), - 'type' => 'activity', - 'date' => $metadataActivity->getTableName() - .'.'.$metadataActivity->getColumnName('date'), - 'FROM' => $this->getFromClause($metadataActivity, $metadataPerson), - 'WHERE' => $this->getWhereClause($metadataActivity, $metadataPerson, - $args['person']) - ); - } - - private function getWhereClause(ClassMetadata $metadataActivity, - ClassMetadata $metadataPerson, Person $person) - { - $role = new Role('CHILL_ACTIVITY_SEE'); - $reachableCenters = $this->helper->getReachableCenters($this->user, - $role); - $associationMapping = $metadataActivity->getAssociationMapping('person'); - - if (count($reachableCenters) === 0) { - return 'FALSE = TRUE'; - } - - // we start with activities having the person_id linked to person - // (currently only context "person" is supported) - $whereClause = sprintf('%s = %d', - $associationMapping['joinColumns'][0]['name'], - $person->getId()); - - // we add acl (reachable center and scopes) - $centerAndScopeLines = array(); - foreach ($reachableCenters as $center) { - $reachablesScopesId = array_map( - function(Scope $scope) { return $scope->getId(); }, - $this->helper->getReachableScopes($this->user, $role, - $person->getCenter()) - ); - - $centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))', - $metadataPerson->getTableName().'.'. - $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], - $center->getId(), - $metadataActivity->getTableName().'.'. - $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], - implode(',', $reachablesScopesId)); - - } - $whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')'; - - return $whereClause; - } - - private function getFromClause(ClassMetadata $metadataActivity, - ClassMetadata $metadataPerson) - { - $associationMapping = $metadataActivity->getAssociationMapping('person'); - - return $metadataActivity->getTableName().' JOIN ' - .$metadataPerson->getTableName().' ON ' - .$metadataPerson->getTableName().'.'. - $associationMapping['joinColumns'][0]['referencedColumnName'] - .' = ' - .$associationMapping['joinColumns'][0]['name'] - ; + + return [ + 'id' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('id'), + 'type' => 'activity', + 'date' => $metadataActivity->getTableName() + . '.' . $metadataActivity->getColumnName('date'), + 'FROM' => $this->getFromClause($metadataActivity, $metadataPerson), + 'WHERE' => $this->getWhereClause( + $metadataActivity, + $metadataPerson, + $args['person'] + ), + ]; } - /** - * - * {@inheritDoc} - */ public function getEntities(array $ids) { $activities = $this->em->getRepository('ChillActivityBundle:Activity') - ->findBy(array('id' => $ids)); - - $result = array(); - foreach($activities as $activity) { + ->findBy(['id' => $ids]); + + $result = []; + + foreach ($activities as $activity) { $result[$activity->getId()] = $activity; } - + return $result; } - /** - * - * {@inheritDoc} - */ public function getEntityTemplate($entity, $context, array $args) { $this->checkContext($context); - - return array( - 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', - 'template_data' => array( - 'activity' => $entity, - 'person' => $args['person'], - 'user' => $entity->getUser() - ) - ); + + return [ + 'template' => 'ChillActivityBundle:Timeline:activity_person_context.html.twig', + 'template_data' => [ + 'activity' => $entity, + 'person' => $args['person'], + 'user' => $entity->getUser(), + ], + ]; + } + + public function supportsType($type) + { + return 'activity' === $type; } /** - * - * {@inheritDoc} - */ - public function supportsType($type) - { - return $type === 'activity'; - } - - /** - * check if the context is supported - * + * check if the context is supported. + * * @param string $context - * @throws \LogicException if the context is not supported + * + * @throws LogicException if the context is not supported */ private function checkContext($context) { - if ($context !== 'person') { - throw new \LogicException("The context '$context' is not " + if ('person' !== $context) { + throw new LogicException("The context '{$context}' is not " . "supported. Currently only 'person' is supported"); } } + private function getFromClause( + ClassMetadata $metadataActivity, + ClassMetadata $metadataPerson + ) { + $associationMapping = $metadataActivity->getAssociationMapping('person'); + + return $metadataActivity->getTableName() . ' JOIN ' + . $metadataPerson->getTableName() . ' ON ' + . $metadataPerson->getTableName() . '.' . + $associationMapping['joinColumns'][0]['referencedColumnName'] + . ' = ' + . $associationMapping['joinColumns'][0]['name']; + } + + private function getWhereClause( + ClassMetadata $metadataActivity, + ClassMetadata $metadataPerson, + Person $person + ) { + $role = new Role('CHILL_ACTIVITY_SEE'); + $reachableCenters = $this->helper->getReachableCenters( + $this->user, + $role + ); + $associationMapping = $metadataActivity->getAssociationMapping('person'); + + if (count($reachableCenters) === 0) { + return 'FALSE = TRUE'; + } + + // we start with activities having the person_id linked to person + // (currently only context "person" is supported) + $whereClause = sprintf( + '%s = %d', + $associationMapping['joinColumns'][0]['name'], + $person->getId() + ); + + // we add acl (reachable center and scopes) + $centerAndScopeLines = []; + + foreach ($reachableCenters as $center) { + $reachablesScopesId = array_map( + function (Scope $scope) { + return $scope->getId(); + }, + $this->helper->getReachableScopes( + $this->user, + $role, + $person->getCenter() + ) + ); + + $centerAndScopeLines[] = sprintf( + '(%s = %d AND %s IN (%s))', + $metadataPerson->getTableName() . '.' . + $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], + $center->getId(), + $metadataActivity->getTableName() . '.' . + $metadataActivity->getAssociationMapping('scope')['joinColumns'][0]['name'], + implode(',', $reachablesScopesId) + ); + } + $whereClause .= ' AND (' . implode(' OR ', $centerAndScopeLines) . ')'; + + return $whereClause; + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20150701091248.php b/src/Bundle/ChillActivityBundle/migrations/Version20150701091248.php index be0eb7221..1a7d66c86 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20150701091248.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20150701091248.php @@ -1,38 +1,40 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Activity; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ class Version20150701091248 extends AbstractMigration { - /** - * @param Schema $schema - */ + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0C59BB1592'); + $this->addSql('ALTER TABLE ActivityReason DROP CONSTRAINT FK_654A2FCD12469DE2'); + $this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0CC54C8C93'); + $this->addSql('DROP SEQUENCE Activity_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE ActivityReason_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE ActivityReasonCategory_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE ActivityType_id_seq CASCADE'); + $this->addSql('DROP TABLE Activity'); + $this->addSql('DROP TABLE ActivityReason'); + $this->addSql('DROP TABLE ActivityReasonCategory'); + $this->addSql('DROP TABLE ActivityType'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -59,25 +61,4 @@ class Version20150701091248 extends AbstractMigration $this->addSql('ALTER TABLE Activity ADD CONSTRAINT FK_55026B0C217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE ActivityReason ADD CONSTRAINT FK_654A2FCD12469DE2 FOREIGN KEY (category_id) REFERENCES ActivityReasonCategory (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0C59BB1592'); - $this->addSql('ALTER TABLE ActivityReason DROP CONSTRAINT FK_654A2FCD12469DE2'); - $this->addSql('ALTER TABLE Activity DROP CONSTRAINT FK_55026B0CC54C8C93'); - $this->addSql('DROP SEQUENCE Activity_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE ActivityReason_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE ActivityReasonCategory_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE ActivityType_id_seq CASCADE'); - $this->addSql('DROP TABLE Activity'); - $this->addSql('DROP TABLE ActivityReason'); - $this->addSql('DROP TABLE ActivityReasonCategory'); - $this->addSql('DROP TABLE ActivityType'); - } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20150702093317.php b/src/Bundle/ChillActivityBundle/migrations/Version20150702093317.php index 0ef11b14f..0dd9798ad 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20150702093317.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20150702093317.php @@ -1,54 +1,22 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Activity; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ class Version20150702093317 extends AbstractMigration { - /** - * @param Schema $schema - */ - public function up(Schema $schema): void - { - // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN label;'); - $this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN name JSON;'); - $this->addSql('ALTER TABLE ActivityReason DROP COLUMN label;'); - $this->addSql('ALTER TABLE ActivityReason ADD COLUMN name JSON;'); - $this->addSql('ALTER TABLE ActivityType DROP COLUMN name;'); - $this->addSql('ALTER TABLE ActivityType ADD COLUMN name JSON;'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs @@ -61,4 +29,17 @@ class Version20150702093317 extends AbstractMigration $this->addSql('ALTER TABLE ActivityType DROP COLUMN name;'); $this->addSql('ALTER TABLE ActivityType ADD COLUMN name VARCHAR(255) NOT NULL;'); } -} \ No newline at end of file + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE ActivityReasonCategory DROP COLUMN label;'); + $this->addSql('ALTER TABLE ActivityReasonCategory ADD COLUMN name JSON;'); + $this->addSql('ALTER TABLE ActivityReason DROP COLUMN label;'); + $this->addSql('ALTER TABLE ActivityReason ADD COLUMN name JSON;'); + $this->addSql('ALTER TABLE ActivityType DROP COLUMN name;'); + $this->addSql('ALTER TABLE ActivityType ADD COLUMN name JSON;'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20150704091347.php b/src/Bundle/ChillActivityBundle/migrations/Version20150704091347.php index 8940b04c3..5dea48f5a 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20150704091347.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20150704091347.php @@ -1,51 +1,22 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Activity; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** - * Db Migration - * + * Db Migration. */ class Version20150704091347 extends AbstractMigration { - /** - * @param Schema $schema - */ - public function up(Schema $schema): void - { - // this up() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE Activity ALTER COLUMN remark DROP NOT NULL;'); - $this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs @@ -54,4 +25,13 @@ class Version20150704091347 extends AbstractMigration $this->addSql('ALTER TABLE Activity ALTER COLUMN remark SET NOT NULL;'); $this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;'); } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE Activity ALTER COLUMN remark DROP NOT NULL;'); + $this->addSql('ALTER TABLE Activity ALTER COLUMN attendee DROP NOT NULL;'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20160222103457.php b/src/Bundle/ChillActivityBundle/migrations/Version20160222103457.php index 0dbcabbb4..6aa355cae 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20160222103457.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20160222103457.php @@ -1,60 +1,31 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); - - // create the new table activity reason - $this->addSql('CREATE TABLE activity_activityreason (' - . 'activity_id INT NOT NULL, ' - . 'activityreason_id INT NOT NULL, ' - . 'PRIMARY KEY(activity_id, activityreason_id))' - ); - $this->addSql('CREATE INDEX IDX_338A864381C06096 ON activity_activityreason (activity_id)'); - $this->addSql('CREATE INDEX IDX_338A8643D771E0FC ON activity_activityreason (activityreason_id)'); - $this->addSql('ALTER TABLE activity_activityreason ' - . 'ADD CONSTRAINT FK_338A864381C06096 FOREIGN KEY (activity_id) ' - . 'REFERENCES Activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE activity_activityreason ' - . 'ADD CONSTRAINT FK_338A8643D771E0FC FOREIGN KEY (activityreason_id) ' - . 'REFERENCES ActivityReason (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - - // migrate old data to new table - $this->addSql('INSERT INTO activity_activityreason (activity_id, activityreason_id) ' - . 'SELECT id, reason_id FROM activity WHERE reason_id IS NOT NULL'); - - - // remove old column - $this->addSql('ALTER TABLE activity DROP CONSTRAINT fk_55026b0c59bb1592'); - $this->addSql('DROP INDEX idx_55026b0c59bb1592'); - $this->addSql('ALTER TABLE activity DROP reason_id'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); $this->addSql('ALTER TABLE Activity ADD reason_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE Activity ADD CONSTRAINT ' @@ -63,17 +34,49 @@ class Version20160222103457 extends AbstractMigration $this->addSql('CREATE INDEX idx_55026b0c59bb1592 ON Activity (reason_id)'); // try to keep at least on activity reason... - $this->addSql('UPDATE activity + $this->addSql( + 'UPDATE activity SET reason_id=rid FROM ( SELECT activity_id AS aid, MIN(activityreason_id) AS rid FROM activity_activityreason GROUP BY activity_id ) AS sb WHERE sb.aid = activity.id' - ); - - + ); + $this->addSql('DROP TABLE activity_activityreason'); - + } + + public function up(Schema $schema): void + { + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + // create the new table activity reason + $this->addSql( + 'CREATE TABLE activity_activityreason (' + . 'activity_id INT NOT NULL, ' + . 'activityreason_id INT NOT NULL, ' + . 'PRIMARY KEY(activity_id, activityreason_id))' + ); + $this->addSql('CREATE INDEX IDX_338A864381C06096 ON activity_activityreason (activity_id)'); + $this->addSql('CREATE INDEX IDX_338A8643D771E0FC ON activity_activityreason (activityreason_id)'); + $this->addSql('ALTER TABLE activity_activityreason ' + . 'ADD CONSTRAINT FK_338A864381C06096 FOREIGN KEY (activity_id) ' + . 'REFERENCES Activity (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE activity_activityreason ' + . 'ADD CONSTRAINT FK_338A8643D771E0FC FOREIGN KEY (activityreason_id) ' + . 'REFERENCES ActivityReason (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + + // migrate old data to new table + $this->addSql('INSERT INTO activity_activityreason (activity_id, activityreason_id) ' + . 'SELECT id, reason_id FROM activity WHERE reason_id IS NOT NULL'); + + // remove old column + $this->addSql('ALTER TABLE activity DROP CONSTRAINT fk_55026b0c59bb1592'); + $this->addSql('DROP INDEX idx_55026b0c59bb1592'); + $this->addSql('ALTER TABLE activity DROP reason_id'); } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php b/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php index 4419c3699..3f2710cfc 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20161114085659.php @@ -1,29 +1,29 @@ addSql('ALTER TABLE activitytype ADD active BOOLEAN NOT NULL DEFAULT \'t\''); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->addSql('ALTER TABLE ActivityType DROP active'); } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype ADD active BOOLEAN NOT NULL DEFAULT \'t\''); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210304154629.php b/src/Bundle/ChillActivityBundle/migrations/Version20210304154629.php index d581bdb3a..427fa5bf2 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210304154629.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210304154629.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE activity ADD comment_comment TEXT DEFAULT NULL'); - $this->addSql('ALTER TABLE activity ADD comment_userId INT DEFAULT NULL'); - $this->addSql('ALTER TABLE activity ADD comment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs @@ -33,4 +27,17 @@ final class Version20210304154629 extends AbstractMigration $this->addSql('ALTER TABLE activity DROP comment_userId'); $this->addSql('ALTER TABLE activity DROP comment_date'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE activity ADD comment_comment TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE activity ADD comment_userId INT DEFAULT NULL'); + $this->addSql('ALTER TABLE activity ADD comment_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL'); + } } diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20210311114250.php b/src/Bundle/ChillActivityBundle/migrations/Version20210311114250.php index 7a3f528b5..135c6e3ad 100644 --- a/src/Bundle/ChillActivityBundle/migrations/Version20210311114250.php +++ b/src/Bundle/ChillActivityBundle/migrations/Version20210311114250.php @@ -1,5 +1,12 @@ addSql('UPDATE activity SET comment_comment = remark'); $this->addSql('ALTER TABLE activity DROP remark'); } - - public function down(Schema $schema) : void - { - // this down() migration is auto-generated, please modify it to your needs - - } } diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php index 91ad6b7bf..3a9290c56 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorInterface.php @@ -1,22 +1,22 @@ - */ interface CalculatorInterface { /** - * * @param AbstractElement[] $elements */ - public function calculate(array $elements) : ?CalculatorResult; - + public function calculate(array $elements): ?CalculatorResult; + public function getAlias(); } diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php index ae90a448e..25f0aca45 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorManager.php @@ -1,67 +1,72 @@ - */ +use OutOfBoundsException; + +use function array_key_exists; +use function array_keys; +use function implode; + class CalculatorManager { /** - * * @var CalculatorInterface[] */ protected $calculators = []; - + protected $defaultCalculator = []; - + public function addCalculator(CalculatorInterface $calculator, bool $default) { $this->calculators[$calculator::getAlias()] = $calculator; - + if ($default) { $this->defaultCalculator[] = $calculator::getAlias(); } } - + /** - * - * @param string $alias - * @return CalculatorInterface - */ - public function getCalculator($alias) - { - if (FALSE === \array_key_exists($alias, $this->calculators)) { - throw new \OutOfBoundsException("The calculator with alias '$alias' does " - . "not exists. Possible values are ". \implode(", ", \array_keys($this->calculators))); - } - - return $this->calculators[$alias]; - } - - /** - * * @param AbstractElement[] $elements + * * @return CalculatorResult[] */ public function calculateDefault(array $elements) { $results = []; - + foreach ($this->defaultCalculator as $alias) { $calculator = $this->calculators[$alias]; $result = $calculator->calculate($elements); - - if ($result !== null) { + + if (null !== $result) { $results[$calculator::getAlias()] = $result; } } - + return $results; } + + /** + * @param string $alias + * + * @return CalculatorInterface + */ + public function getCalculator($alias) + { + if (false === array_key_exists($alias, $this->calculators)) { + throw new OutOfBoundsException("The calculator with alias '{$alias}' does " + . 'not exists. Possible values are ' . implode(', ', array_keys($this->calculators))); + } + + return $this->calculators[$alias]; + } } diff --git a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php index 1066dab25..e99edab6d 100644 --- a/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php +++ b/src/Bundle/ChillBudgetBundle/Calculator/CalculatorResult.php @@ -1,23 +1,25 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\BudgetBundle\Calculator; + class CalculatorResult { - const TYPE_RATE = 'rate'; - const TYPE_CURRENCY = 'currency'; - const TYPE_PERCENTAGE = 'percentage'; - - public $type; - - public $result; - + public const TYPE_CURRENCY = 'currency'; + + public const TYPE_PERCENTAGE = 'percentage'; + + public const TYPE_RATE = 'rate'; + public $label; + + public $result; + + public $type; } diff --git a/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php b/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php index 0d68e1cbf..60f848056 100644 --- a/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php +++ b/src/Bundle/ChillBudgetBundle/ChillAMLIBudgetBundle.php @@ -1,16 +1,23 @@ addCompilerPass(new CalculatorCompilerPass()); } } diff --git a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php index 2cc579d6b..1302b8414 100644 --- a/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php +++ b/src/Bundle/ChillBudgetBundle/Config/ConfigRepository.php @@ -1,72 +1,68 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\BudgetBundle\Config; + class ConfigRepository { /** - * - * @var array - */ - protected $resources; - - /** - * * @var array */ protected $charges; - + + /** + * @var array + */ + protected $resources; + public function __construct($resources, $charges) { $this->resources = $resources; $this->charges = $charges; } - + /** - * - * @return array where keys are the resource'key and label the ressource label - */ - public function getResourcesLabels() - { - $resources = array(); - - foreach ($this->resources as $definition) { - $resources[$definition['key']] = $this->normalizeLabel($definition['labels']); - } - - return $resources; - } - - /** - * * @return array where keys are the resource'key and label the ressource label */ public function getChargesLabels() { - $charges = array(); - + $charges = []; + foreach ($this->charges as $definition) { $charges[$definition['key']] = $this->normalizeLabel($definition['labels']); } - + return $charges; } - - private function normalizeLabel($labels) + + /** + * @return array where keys are the resource'key and label the ressource label + */ + public function getResourcesLabels() { - $normalizedLabels = array(); - + $resources = []; + + foreach ($this->resources as $definition) { + $resources[$definition['key']] = $this->normalizeLabel($definition['labels']); + } + + return $resources; + } + + private function normalizeLabel($labels) + { + $normalizedLabels = []; + foreach ($labels as $labelDefinition) { $normalizedLabels[$labelDefinition['lang']] = $labelDefinition['label']; } - + return $normalizedLabels; } - } diff --git a/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php b/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php index 9ef3758b0..fd4f77f93 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/AbstractElementController.php @@ -1,38 +1,42 @@ createNewElement() - ->setPerson($person) - ; - - $this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $element); - - $form = $this->createForm($this->getType(), $element); - $form->add('submit', SubmitType::class); - - $form->handleRequest($request); - - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($element); - $em->flush(); - - $this->addFlash('success', $this->translator->trans($flashMessageOnSuccess)); - - return $this->redirectToRoute('chill_budget_elements_index', [ - 'id' => $person->getId() - ]); - } elseif ($form->isSubmitted()) { - $this->addFlash('error', $this->translator->trans('This form contains errors')); - } - - return $this->render($template, array( - 'form' => $form->createView(), - 'person' => $person, - 'element' => $element - )); - } - - /** - * - * @param AbstractElement $element - * @param Request $request - * @param string $template - * @param string $flashOnSuccess - * @return \Symfony\Component\HttpFoundation\Response - */ - protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess) - { - $this->denyAccessUnlessGranted(BudgetElementVoter::UPDATE, $element); - - $form = $this->createForm($this->getType(), $element); - $form->add('submit', SubmitType::class); - - $form->handleRequest($request); - - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->flush(); - - $this->addFlash('success', $this->translator->trans($flashOnSuccess)); - - return $this->redirectToRoute('chill_budget_elements_index', [ - 'id' => $element->getPerson()->getId() - ]); - } - - return $this->render($template, array( - 'element' => $element, - 'form' => $form->createView(), - 'person' => $element->getPerson() - )); - } - - /** - * * Route( * "{_locale}/family-members/family-members/{id}/delete", * name="chill_family_members_family_members_delete" - * ) - * - * @param AbstractElement $element - * @param Request $request + * ). + * + * @param mixed $template + * @param mixed $flashMessage + * * @return \Symfony\Component\BrowserKit\Response */ protected function _delete(AbstractElement $element, Request $request, $template, $flashMessage) @@ -145,63 +69,140 @@ abstract class AbstractElementController extends Controller $form->handleRequest($request); if ($form->isValid()) { - $this->chillMainLogger->notice("A budget element has been removed", array( - 'family_element' => get_class($element), - 'by_user' => $this->getUser()->getUsername(), - 'family_member_id' => $element->getId(), - 'amount' => $element->getAmount(), - 'type' => $element->getType() - )); + $this->chillMainLogger->notice('A budget element has been removed', [ + 'family_element' => get_class($element), + 'by_user' => $this->getUser()->getUsername(), + 'family_member_id' => $element->getId(), + 'amount' => $element->getAmount(), + 'type' => $element->getType(), + ]); $em = $this->getDoctrine()->getManager(); $em->remove($element); $em->flush(); $this->addFlash('success', $this->translator - ->trans($flashMessage)); + ->trans($flashMessage)); - return $this->redirectToRoute('chill_budget_elements_index', array( - 'id' => $element->getPerson()->getId() - )); + return $this->redirectToRoute('chill_budget_elements_index', [ + 'id' => $element->getPerson()->getId(), + ]); } } - - return $this->render($template, array( - 'element' => $element, - 'delete_form' => $form->createView() - )); + return $this->render($template, [ + 'element' => $element, + 'delete_form' => $form->createView(), + ]); } - + + /** + * @param string $template + * @param string $flashOnSuccess + * + * @return \Symfony\Component\HttpFoundation\Response + */ + protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess) + { + $this->denyAccessUnlessGranted(BudgetElementVoter::UPDATE, $element); + + $form = $this->createForm($this->getType(), $element); + $form->add('submit', SubmitType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() and $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->flush(); + + $this->addFlash('success', $this->translator->trans($flashOnSuccess)); + + return $this->redirectToRoute('chill_budget_elements_index', [ + 'id' => $element->getPerson()->getId(), + ]); + } + + return $this->render($template, [ + 'element' => $element, + 'form' => $form->createView(), + 'person' => $element->getPerson(), + ]); + } + + /** + * @param mixed $template + * @param mixed $flashMessageOnSuccess + */ + protected function _new(Person $person, Request $request, $template, $flashMessageOnSuccess) + { + /* @var $element \Chill\AMLI\BudgetBundle\Entity\AbstractElement */ + $element = $this->createNewElement() + ->setPerson($person); + + $this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $element); + + $form = $this->createForm($this->getType(), $element); + $form->add('submit', SubmitType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() and $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($element); + $em->flush(); + + $this->addFlash('success', $this->translator->trans($flashMessageOnSuccess)); + + return $this->redirectToRoute('chill_budget_elements_index', [ + 'id' => $person->getId(), + ]); + } + + if ($form->isSubmitted()) { + $this->addFlash('error', $this->translator->trans('This form contains errors')); + } + + return $this->render($template, [ + 'form' => $form->createView(), + 'person' => $person, + 'element' => $element, + ]); + } + /** * Route( * "{_locale}/family-members/family-members/{id}/view", * name="chill_family_members_family_members_view" - * ) + * ). + * + * @param mixed $template */ protected function _view(AbstractElement $element, $template) { $this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $element); - - return $this->render($template, array( - 'element' => $element - )); + + return $this->render($template, [ + 'element' => $element, + ]); } - + + /** + * @return AbstractElement the newly created element + */ + abstract protected function createNewElement(); + + abstract protected function getType(); + /** * 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() { return $this->createFormBuilder() ->setMethod(Request::METHOD_DELETE) - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); } - } diff --git a/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php b/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php index 370d1abb2..50e7bacd1 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ChargeController.php @@ -1,102 +1,96 @@ - */ class ChargeController extends AbstractElementController { - protected function getType() - { - return ChargeType::class; - } - - protected function createNewElement() - { - return new Charge(); - } - /** - * * @Route( - * "{_locale}/budget/charge/{id}/view", - * name="chill_budget_charge_view" + * "{_locale}/budget/charge/{id}/delete", + * name="chill_budget_charge_delete" * ) - * @param Charge $charge + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function deleteAction(Request $request, Charge $charge) + { + return $this->_delete( + $charge, + $request, + '@ChillAMLIBudget/Charge/confirm_delete.html.twig', + 'Charge deleted' + ); + } + + /** + * @Route( + * "{_locale}/budget/charge/{id}/edit", + * name="chill_budget_charge_edit" + * ) + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function editAction(Request $request, Charge $charge) + { + return $this->_edit( + $charge, + $request, + '@ChillAMLIBudget/Charge/edit.html.twig', + 'Charge updated' + ); + } + + /** + * @Route( + * "{_locale}/budget/charge/by-person/{id}/new", + * name="chill_budget_charge_new" + * ) + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function newAction(Request $request, Person $person) + { + return $this->_new( + $person, + $request, + '@ChillAMLIBudget/Charge/new.html.twig', + 'Charge created' + ); + } + + /** + * @Route( + * "{_locale}/budget/charge/{id}/view", + * name="chill_budget_charge_view" + * ) + * * @return \Symfony\Component\HttpFoundation\Response */ public function viewAction(Charge $charge) { return $this->_view($charge, '@ChillAMLIBudget/Charge/view.html.twig'); } - - /** - * @Route( - * "{_locale}/budget/charge/by-person/{id}/new", - * name="chill_budget_charge_new" - * ) - * - * @param Request $request - * @param Person $person - * @return \Symfony\Component\HttpFoundation\Response - */ - public function newAction(Request $request, Person $person) + + protected function createNewElement() { - return $this->_new( - $person, - $request, - '@ChillAMLIBudget/Charge/new.html.twig', - 'Charge created'); + return new Charge(); } - - /** - * @Route( - * "{_locale}/budget/charge/{id}/edit", - * name="chill_budget_charge_edit" - * ) - * - * @param Request $request - * @param Charge $charge - * @return \Symfony\Component\HttpFoundation\Response - */ - public function editAction(Request $request, Charge $charge) + + protected function getType() { - return $this->_edit( - $charge, - $request, - '@ChillAMLIBudget/Charge/edit.html.twig', - 'Charge updated'); - } - - /** - * - * @Route( - * "{_locale}/budget/charge/{id}/delete", - * name="chill_budget_charge_delete" - * ) - * - * @param Request $request - * @param Charge $charge - * @return \Symfony\Component\HttpFoundation\Response - */ - public function deleteAction(Request $request, Charge $charge) - { - return $this->_delete( - $charge, - $request, - '@ChillAMLIBudget/Charge/confirm_delete.html.twig', - 'Charge deleted'); + return ChargeType::class; } } diff --git a/src/Bundle/ChillBudgetBundle/Controller/ElementController.php b/src/Bundle/ChillBudgetBundle/Controller/ElementController.php index d5f6b4bea..8587f5bac 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ElementController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ElementController.php @@ -1,46 +1,50 @@ chillMainLogger = $chillMainLogger; $this->calculator = $calculator; } - + /** * @Route( - * "{_locale}/budget/elements/by-person/{id}", - * name="chill_budget_elements_index" + * "{_locale}/budget/elements/by-person/{id}", + * name="chill_budget_elements_index" * ) */ public function indexAction(Person $person) { $this->denyAccessUnlessGranted(BudgetElementVoter::SHOW, $person); - + $charges = $this->em ->getRepository(Charge::class) ->findByPerson($person); $ressources = $this->em ->getRepository(Resource::class) ->findByPerson($person); - - $now = new \DateTime('now'); - + + $now = new DateTime('now'); + $actualCharges = $this->em ->getRepository(Charge::class) ->findByPersonAndDate($person, $now); $actualResources = $this->em ->getRepository(Resource::class) ->findByPersonAndDate($person, $now); - - $elements = \array_merge($actualCharges, $actualResources); - + + $elements = array_merge($actualCharges, $actualResources); + if (count($elements) > 0) { $results = $this->calculator->calculateDefault($elements); } - - return $this->render('ChillAMLIBudgetBundle:Element:index.html.twig', array( + + return $this->render('ChillAMLIBudgetBundle:Element:index.html.twig', [ 'person' => $person, 'charges' => $charges, 'resources' => $ressources, - 'results' => $results ?? [] - )); + 'results' => $results ?? [], + ]); } - } diff --git a/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php b/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php index 8b252ea48..7ab00a798 100644 --- a/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php +++ b/src/Bundle/ChillBudgetBundle/Controller/ResourceController.php @@ -1,103 +1,96 @@ - */ class ResourceController extends AbstractElementController { - - protected function getType() - { - return ResourceType::class; - } - - protected function createNewElement() - { - return new Resource(); - } - /** - * * @Route( - * "{_locale}/budget/resource/{id}/view", - * name="chill_budget_resource_view" + * "{_locale}/budget/resource/{id}/delete", + * name="chill_budget_resource_delete" * ) - * @param Request $request - * @param Resource $resource + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function deleteAction(Request $request, Resource $resource) + { + return $this->_delete( + $resource, + $request, + '@ChillAMLIBudget/Resource/confirm_delete.html.twig', + 'Resource deleted' + ); + } + + /** + * @Route( + * "{_locale}/budget/resource/{id}/edit", + * name="chill_budget_resource_edit" + * ) + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function editAction(Request $request, Resource $resource) + { + return $this->_edit( + $resource, + $request, + '@ChillAMLIBudget/Resource/edit.html.twig', + 'Resource updated' + ); + } + + /** + * @Route( + * "{_locale}/budget/resource/by-person/{id}/new", + * name="chill_budget_resource_new" + * ) + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function newAction(Request $request, Person $person) + { + return $this->_new( + $person, + $request, + '@ChillAMLIBudget/Resource/new.html.twig', + 'Resource created' + ); + } + + /** + * @Route( + * "{_locale}/budget/resource/{id}/view", + * name="chill_budget_resource_view" + * ) + * * @return \Symfony\Component\HttpFoundation\Response */ public function viewAction(Resource $resource) { return $this->_view($resource, '@ChillAMLIBudget/Resource/view.html.twig'); } - - /** - * @Route( - * "{_locale}/budget/resource/by-person/{id}/new", - * name="chill_budget_resource_new" - * ) - * - * @param Request $request - * @param Person $person - * @return \Symfony\Component\HttpFoundation\Response - */ - public function newAction(Request $request, Person $person) + + protected function createNewElement() { - return $this->_new( - $person, - $request, - '@ChillAMLIBudget/Resource/new.html.twig', - 'Resource created'); + return new Resource(); } - - /** - * @Route( - * "{_locale}/budget/resource/{id}/edit", - * name="chill_budget_resource_edit" - * ) - * - * @param Request $request - * @param Resource $resource - * @return \Symfony\Component\HttpFoundation\Response - */ - public function editAction(Request $request, Resource $resource) + + protected function getType() { - return $this->_edit( - $resource, - $request, - '@ChillAMLIBudget/Resource/edit.html.twig', - 'Resource updated'); - } - - /** - * - * @Route( - * "{_locale}/budget/resource/{id}/delete", - * name="chill_budget_resource_delete" - * ) - * - * @param Request $request - * @param Resource $resource - * @return \Symfony\Component\HttpFoundation\Response - */ - public function deleteAction(Request $request, Resource $resource) - { - return $this->_delete($resource, - $request, - '@ChillAMLIBudget/Resource/confirm_delete.html.twig', - 'Resource deleted'); + return ResourceType::class; } } diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php index edbf226b6..9ef18763f 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/ChillAMLIBudgetExtension.php @@ -1,30 +1,34 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services/config.yaml'); $loader->load('services/form.yaml'); $loader->load('services/security.yaml'); @@ -32,7 +36,7 @@ class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInte $loader->load('services/templating.yaml'); $loader->load('services/menu.yaml'); $loader->load('services/calculator.yaml'); - + $this->storeConfig('resources', $config, $container); $this->storeConfig('charges', $config, $container); } @@ -42,36 +46,35 @@ class ChillAMLIBudgetExtension extends Extension implements PrependExtensionInte $this->prependAuthorization($container); $this->prependRoutes($container); } - - protected function storeConfig($position, array $config, ContainerBuilder $container) + + /* (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() + */ + public function prependRoutes(ContainerBuilder $container) { - $container - ->setParameter(sprintf('chill_budget.%s', $position), $config[$position]) - ; + //add routes for custom bundle + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillAMLIBudgetBundle/config/routing.yaml', + ], + ], + ]); } protected function prependAuthorization(ContainerBuilder $container) { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - BudgetElementVoter::UPDATE => [ BudgetElementVoter::SHOW ], - BudgetElementVoter::CREATE => [ BudgetElementVoter::SHOW ] - ) - )); + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + BudgetElementVoter::UPDATE => [BudgetElementVoter::SHOW], + BudgetElementVoter::CREATE => [BudgetElementVoter::SHOW], + ], + ]); } - - /* (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() - */ - public function prependRoutes(ContainerBuilder $container) + + protected function storeConfig($position, array $config, ContainerBuilder $container) { - //add routes for custom bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillAMLIBudgetBundle/config/routing.yaml' - ) - ) - )); + $container + ->setParameter(sprintf('chill_budget.%s', $position), $config[$position]); } } diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php index 30e5ae8da..7e750868f 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/Compiler/CalculatorCompilerPass.php @@ -1,29 +1,29 @@ - */ class CalculatorCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $manager = $container->getDefinition('Chill\AMLI\BudgetBundle\Calculator\CalculatorManager'); - + foreach ($container->findTaggedServiceIds('chill_budget.calculator') as $id => $tags) { - foreach($tags as $tag) { + foreach ($tags as $tag) { $reference = new Reference($id); - $manager->addMethodCall('addCalculator', [ $reference, $tag['default'] ?? false ]); + $manager->addMethodCall('addCalculator', [$reference, $tag['default'] ?? false]); } } } diff --git a/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php index 1e1769d89..bfc4c4705 100644 --- a/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillBudgetBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ getRootNode('chill_amli_budget'); - + $rootNode ->children() - + // ressources - ->arrayNode('resources')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('key')->isRequired()->cannotBeEmpty() - ->info('the key stored in database') - ->example('salary') - ->end() - ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('Salaire') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - - ->arrayNode('charges')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('key')->isRequired()->cannotBeEmpty() - ->info('the key stored in database') - ->example('salary') - ->end() - ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('Salaire') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - + ->arrayNode('resources')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('key')->isRequired()->cannotBeEmpty() + ->info('the key stored in database') + ->example('salary') ->end() - ; + ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('Salaire') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->arrayNode('charges')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('key')->isRequired()->cannotBeEmpty() + ->info('the key stored in database') + ->example('salary') + ->end() + ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('Salaire') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + + ->end(); return $treeBuilder; } diff --git a/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php b/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php index 985af9676..72fa2b88d 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php +++ b/src/Bundle/ChillBudgetBundle/Entity/AbstractElement.php @@ -1,46 +1,38 @@ amount; + } + + /** + * Get comment. + * + * @return string|null + */ + public function getComment() + { + return $this->comment; + } + + /** + * Get endDate. + * + * @return DateTimeImmutable|null + */ + public function getEndDate() + { + return $this->endDate; + } + public function getPerson(): Person { return $this->person; } - public function setPerson(Person $person) - { - $this->person = $person; - - return $this; - } - /** - * Set type. + * Get startDate. * - * @param string $type - * - * @return AbstractElement + * @return DateTimeImmutable */ - public function setType($type) + public function getStartDate() { - $this->type = $type; - - return $this; + return $this->startDate; } /** @@ -110,6 +132,15 @@ abstract class AbstractElement return $this->type; } + abstract public function isCharge(): bool; + + public function isEmpty() + { + return 0 == $this->amount; + } + + abstract public function isResource(): bool; + /** * Set amount. * @@ -124,16 +155,6 @@ abstract class AbstractElement return $this; } - /** - * Get amount. - * - * @return double - */ - public function getAmount() - { - return (double) $this->amount; - } - /** * Set comment. * @@ -149,27 +170,40 @@ abstract class AbstractElement } /** - * Get comment. + * Set endDate. * - * @return string|null + * @return AbstractElement */ - public function getComment() + public function setEndDate(?DateTimeInterface $endDate = null) { - return $this->comment; + if ($endDate instanceof DateTime) { + $this->endDate = DateTimeImmutable::createFromMutable($endDate); + } elseif (null === $endDate) { + $this->endDate = null; + } else { + $this->endDate = $endDate; + } + + return $this; + } + + public function setPerson(Person $person) + { + $this->person = $person; + + return $this; } /** * Set startDate. * - * @param \DateTimeInterface $startDate - * * @return AbstractElement */ - public function setStartDate(\DateTimeInterface $startDate) + public function setStartDate(DateTimeInterface $startDate) { - if ($startDate instanceof \DateTime) { - $this->startDate = \DateTimeImmutable::createFromMutable($startDate); - } elseif (NULL === $startDate) { + if ($startDate instanceof DateTime) { + $this->startDate = DateTimeImmutable::createFromMutable($startDate); + } elseif (null === $startDate) { $this->startDate = null; } else { $this->startDate = $startDate; @@ -179,47 +213,16 @@ abstract class AbstractElement } /** - * Get startDate. + * Set type. * - * @return \DateTimeImmutable - */ - public function getStartDate() - { - return $this->startDate; - } - - /** - * Set endDate. - * - * @param \DateTimeInterface|null $endDate + * @param string $type * * @return AbstractElement */ - public function setEndDate(\DateTimeInterface $endDate = null) + public function setType($type) { - if ($endDate instanceof \DateTime) { - $this->endDate = \DateTimeImmutable::createFromMutable($endDate); - } elseif (NULL === $endDate) { - $this->endDate = null; - } else { - $this->endDate = $endDate; - } + $this->type = $type; return $this; } - - /** - * Get endDate. - * - * @return \DateTimeImmutable|null - */ - public function getEndDate() - { - return $this->endDate; - } - - public function isEmpty() - { - return $this->amount == 0; - } } diff --git a/src/Bundle/ChillBudgetBundle/Entity/Charge.php b/src/Bundle/ChillBudgetBundle/Entity/Charge.php index a330c382d..455bb9043 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/Charge.php +++ b/src/Bundle/ChillBudgetBundle/Entity/Charge.php @@ -1,18 +1,47 @@ setStartDate(new \DateTimeImmutable('today')); + $this->setStartDate(new DateTimeImmutable('today')); + } + + public function getCenter(): \Chill\MainBundle\Entity\Center + { + return $this->getPerson()->getCenter(); + } + + public function getHelp() + { + return $this->help; } /** @@ -56,23 +75,6 @@ class Charge extends AbstractElement implements HasCenterInterface { return $this->id; } - - public function getHelp() - { - return $this->help; - } - - public function setHelp($help) - { - $this->help = $help; - - return $this; - } - - public function getCenter(): \Chill\MainBundle\Entity\Center - { - return $this->getPerson()->getCenter(); - } public function isCharge(): bool { @@ -83,4 +85,11 @@ class Charge extends AbstractElement implements HasCenterInterface { return false; } + + public function setHelp($help) + { + $this->help = $help; + + return $this; + } } diff --git a/src/Bundle/ChillBudgetBundle/Entity/Resource.php b/src/Bundle/ChillBudgetBundle/Entity/Resource.php index 390268592..9963de94c 100644 --- a/src/Bundle/ChillBudgetBundle/Entity/Resource.php +++ b/src/Bundle/ChillBudgetBundle/Entity/Resource.php @@ -1,12 +1,20 @@ setStartDate(new \DateTimeImmutable('today')); + $this->setStartDate(new DateTimeImmutable('today')); + } + + public function getCenter(): \Chill\MainBundle\Entity\Center + { + return $this->getPerson()->getCenter(); } - /** * Get id. * @@ -38,11 +50,6 @@ class Resource extends AbstractElement implements HasCenterInterface return $this->id; } - public function getCenter(): \Chill\MainBundle\Entity\Center - { - return $this->getPerson()->getCenter(); - } - public function isCharge(): bool { return false; diff --git a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php index da219abb9..8d4c59f5d 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ChargeType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ChargeType.php @@ -1,124 +1,120 @@ configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('type', ChoiceType::class, [ 'choices' => $this->getTypes(), - 'placeholder' => 'Choose a charge type' + 'placeholder' => 'Choose a charge type', ]) ->add('amount', MoneyType::class) ->add('comment', TextAreaType::class, [ - 'required' => false - ]) - ; - + 'required' => false, + ]); + if ($options['show_start_date']) { $builder->add('startDate', ChillDateType::class, [ - 'label' => 'Start of validity period' + 'label' => 'Start of validity period', ]); } - + if ($options['show_end_date']) { $builder->add('endDate', ChillDateType::class, [ 'required' => false, - 'label' => 'End of validity period' + 'label' => 'End of validity period', ]); } - + if ($options['show_help']) { $builder->add('help', ChoiceType::class, [ 'choices' => [ 'charge.help.running' => Charge::HELP_ASKED, 'charge.help.no' => Charge::HELP_NO, 'charge.help.yes' => Charge::HELP_YES, - 'charge.help.not-concerned' => Charge::HELP_NOT_RELEVANT + 'charge.help.not-concerned' => Charge::HELP_NOT_RELEVANT, ], 'placeholder' => 'Choose a status', 'required' => false, - 'label' => 'Help to pay charges' + 'label' => 'Help to pay charges', ]); } } - - private function getTypes() - { - $charges = $this->configRepository - ->getChargesLabels(); - - // rewrite labels to filter in language - foreach ($charges as $key => $labels) { - $charges[$key] = $this->translatableStringHelper->localize($labels); - } - - \asort($charges); - - return \array_flip($charges); - } - - /** - * {@inheritdoc} - */ + public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => 'Chill\AMLI\BudgetBundle\Entity\Charge', 'show_start_date' => true, 'show_end_date' => true, - 'show_help' => true - )); - + 'show_help' => true, + ]); + $resolver ->setAllowedTypes('show_start_date', 'boolean') ->setAllowedTypes('show_end_date', 'boolean') - ->setAllowedTypes('show_help', 'boolean') - ; + ->setAllowedTypes('show_help', 'boolean'); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_amli_budgetbundle_charge'; } + private function getTypes() + { + $charges = $this->configRepository + ->getChargesLabels(); + // rewrite labels to filter in language + foreach ($charges as $key => $labels) { + $charges[$key] = $this->translatableStringHelper->localize($labels); + } + + asort($charges); + + return array_flip($charges); + } } diff --git a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php index abf7191ab..b32b7253b 100644 --- a/src/Bundle/ChillBudgetBundle/Form/ResourceType.php +++ b/src/Bundle/ChillBudgetBundle/Form/ResourceType.php @@ -1,108 +1,104 @@ configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('type', ChoiceType::class, [ 'choices' => $this->getTypes(), 'placeholder' => 'Choose a resource type', - 'label' => 'Resource element type' + 'label' => 'Resource element type', ]) ->add('amount', MoneyType::class) ->add('comment', TextAreaType::class, [ - 'required' => false - ]) - ; - + 'required' => false, + ]); + if ($options['show_start_date']) { $builder->add('startDate', ChillDateType::class, [ - 'label' => 'Start of validity period' + 'label' => 'Start of validity period', ]); } - + if ($options['show_end_date']) { $builder->add('endDate', ChillDateType::class, [ 'required' => false, - 'label' => 'End of validity period' + 'label' => 'End of validity period', ]); } } - - private function getTypes() - { - $resources = $this->configRepository - ->getResourcesLabels(); - - // rewrite labels to filter in language - foreach ($resources as $key => $labels) { - $resources[$key] = $this->translatableStringHelper->localize($labels); - } - - asort($resources); - - return \array_flip($resources); - } - - /** - * {@inheritdoc} - */ + public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => Resource::class, 'show_start_date' => true, - 'show_end_date' => true - )); - + 'show_end_date' => true, + ]); + $resolver ->setAllowedTypes('show_start_date', 'boolean') - ->setAllowedTypes('show_end_date', 'boolean') - ; + ->setAllowedTypes('show_end_date', 'boolean'); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_amli_budgetbundle_resource'; } + private function getTypes() + { + $resources = $this->configRepository + ->getResourcesLabels(); + // rewrite labels to filter in language + foreach ($resources as $key => $labels) { + $resources[$key] = $this->translatableStringHelper->localize($labels); + } + + asort($resources); + + return array_flip($resources); + } } diff --git a/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php index f2b395267..7b8705511 100644 --- a/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillBudgetBundle/Menu/UserMenuBuilder.php @@ -1,60 +1,59 @@ - */ class UserMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( - AuthorizationCheckerInterface $authorizationChecker, + AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator ) { $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person']; - + if ($this->authorizationChecker->isGranted(BudgetElementVoter::SHOW, $person)) { $menu->addChild( - $this->translator->trans('Budget'), [ + $this->translator->trans('Budget'), + [ 'route' => 'chill_budget_elements_index', - 'routeParameters' => [ 'id' => $person->getId() ], - ]) - ->setExtra('order', 460) - ; + 'routeParameters' => ['id' => $person->getId()], + ] + ) + ->setExtra('order', 460); } } public static function getMenuIds(): array { - return [ 'person' ]; + return ['person']; } } diff --git a/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php b/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php index 73a310d24..c8cb7cab0 100644 --- a/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php +++ b/src/Bundle/ChillBudgetBundle/Repository/ChargeRepository.php @@ -1,35 +1,42 @@ createQueryBuilder('c'); - + $qb->where('c.person = :person') ->andWhere('c.startDate < :date') - ->andWhere('c.startDate < :date OR c.startDate IS NULL') - ; - - if ($sort !== null) { + ->andWhere('c.startDate < :date OR c.startDate IS NULL'); + + if (null !== $sort) { $qb->orderBy($sort); } - + $qb->setParameters([ 'person' => $person, - 'date' => $date + 'date' => $date, ]); - + return $qb->getQuery()->getResult(); } } diff --git a/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php b/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php index 50197ce65..91bd7f258 100644 --- a/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php +++ b/src/Bundle/ChillBudgetBundle/Repository/ResourceRepository.php @@ -1,35 +1,42 @@ createQueryBuilder('c'); - + $qb->where('c.person = :person') ->andWhere('c.startDate < :date') - ->andWhere('c.startDate < :date OR c.startDate IS NULL') - ; - - if ($sort !== null) { + ->andWhere('c.startDate < :date OR c.startDate IS NULL'); + + if (null !== $sort) { $qb->orderBy($sort); } - + $qb->setParameters([ 'person' => $person, - 'date' => $date + 'date' => $date, ]); - + return $qb->getQuery()->getResult(); } } diff --git a/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20180522080432.php b/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20180522080432.php index b326cb452..e2842b1e1 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20180522080432.php +++ b/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20180522080432.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE SCHEMA chill_budget CASCADE'); + } + public function up(Schema $schema) { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -28,14 +44,5 @@ final class Version20180522080432 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_budget.charge.endDate IS \'(DC2Type:datetime_immutable)\''); $this->addSql('ALTER TABLE chill_budget.resource ADD CONSTRAINT FK_5E0A5E97217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_budget.charge ADD CONSTRAINT FK_5C99D2C3217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - public function down(Schema $schema) - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('CREATE SCHEMA chill_budget CASCADE'); - } } diff --git a/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20181219145631.php b/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20181219145631.php index b9c01cd7c..059d7f2c1 100644 --- a/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20181219145631.php +++ b/src/Bundle/ChillBudgetBundle/Resources/migrations/Version20181219145631.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_budget.charge ALTER help DROP NOT NULL'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->addSql('ALTER TABLE chill_budget.charge ALTER help SET NOT NULL'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_budget.charge ALTER help DROP NOT NULL'); + } } diff --git a/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php b/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php index 2f7530938..82c138d96 100644 --- a/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php +++ b/src/Bundle/ChillBudgetBundle/Security/Authorization/BudgetElementVoter.php @@ -1,79 +1,81 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\BudgetBundle\Security\Authorization; + +use Chill\AMLI\BudgetBundle\Entity\AbstractElement; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; +use Chill\PersonBundle\Entity\Person; +use Symfony\Component\Security\Core\Role\Role; + +use function in_array; + class BudgetElementVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_BUDGET_ELEMENT_CREATE'; - const DELETE = 'CHILL_BUDGET_ELEMENT_DELETE'; - const UPDATE = 'CHILL_BUDGET_ELEMENT_UPDATE'; - const SHOW = 'CHILL_BUDGET_ELEMENT_SHOW'; - - const ROLES = [ + public const CREATE = 'CHILL_BUDGET_ELEMENT_CREATE'; + + public const DELETE = 'CHILL_BUDGET_ELEMENT_DELETE'; + + public const ROLES = [ self::CREATE, self::DELETE, self::SHOW, - self::UPDATE + self::UPDATE, ]; - + + public const SHOW = 'CHILL_BUDGET_ELEMENT_SHOW'; + + public const UPDATE = 'CHILL_BUDGET_ELEMENT_UPDATE'; + /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + public function __construct(AuthorizationHelper $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } - - protected function supports($attribute, $subject) - { - return (\in_array($attribute, self::ROLES) && $subject instanceof AbstractElement) - or - ($subject instanceof Person && \in_array($attribute, [ self::SHOW, self::CREATE ])); - } - - protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token) - { - $user = $token->getUser(); - - if (FALSE === $user instanceof User) { - return false; - } - - return $this->authorizationHelper - ->userHasAccess($user, $subject, new Role($attribute)); - } - public function getRoles() { return self::ROLES; - } - + } + public function getRolesWithHierarchy(): array { - return [ 'Budget elements' => self::ROLES ]; - } - + return ['Budget elements' => self::ROLES]; + } + public function getRolesWithoutScope() { return self::ROLES; } + protected function supports($attribute, $subject) + { + return (in_array($attribute, self::ROLES) && $subject instanceof AbstractElement) + or ($subject instanceof Person && in_array($attribute, [self::SHOW, self::CREATE])); + } + + protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token) + { + $user = $token->getUser(); + + if (false === $user instanceof User) { + return false; + } + + return $this->authorizationHelper + ->userHasAccess($user, $subject, new Role($attribute)); + } } diff --git a/src/Bundle/ChillBudgetBundle/Templating/Twig.php b/src/Bundle/ChillBudgetBundle/Templating/Twig.php index f20d4cf84..aba53f3c4 100644 --- a/src/Bundle/ChillBudgetBundle/Templating/Twig.php +++ b/src/Bundle/ChillBudgetBundle/Templating/Twig.php @@ -1,65 +1,63 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\BudgetBundle\Templating; + +use Chill\AMLI\BudgetBundle\Config\ConfigRepository; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Twig\Extension\AbstractExtension; +use Twig\TwigFilter; +use UnexpectedValueException; + class Twig extends AbstractExtension { /** - * * @var ConfigRepository */ protected $configRepository; - + /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct( - ConfigRepository $configRepository, + ConfigRepository $configRepository, TranslatableStringHelper $translatableStringHelper ) { $this->configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - - public function getFilters() - { - return [ - new TwigFilter('budget_element_type_display', [ $this, 'displayLink' ], [ 'is_safe' => [ 'html' ]]) - ]; - } - public function displayLink($link, $family) { - switch($family) { + switch ($family) { case 'resource': return $this->translatableStringHelper->localize( $this->configRepository->getResourcesLabels()[$link] - ); + ); + case 'charge': return $this->translatableStringHelper->localize( $this->configRepository->getChargesLabels()[$link] - ); + ); + default: - throw new \UnexpectedValueException("This family of element: $family is not " + throw new UnexpectedValueException("This family of element: {$family} is not " . "supported. Supported families are 'resource', 'charge'"); } - } + public function getFilters() + { + return [ + new TwigFilter('budget_element_type_display', [$this, 'displayLink'], ['is_safe' => ['html']]), + ]; + } } diff --git a/src/Bundle/ChillBudgetBundle/Tests/Controller/ElementControllerTest.php b/src/Bundle/ChillBudgetBundle/Tests/Controller/ElementControllerTest.php index b672d51ef..c25e2cc36 100644 --- a/src/Bundle/ChillBudgetBundle/Tests/Controller/ElementControllerTest.php +++ b/src/Bundle/ChillBudgetBundle/Tests/Controller/ElementControllerTest.php @@ -1,18 +1,22 @@ request('GET', '/list'); - } - public function testIndex() { $client = static::createClient(); @@ -20,4 +24,10 @@ class ElementControllerTest extends WebTestCase $crawler = $client->request('GET', '/index'); } + public function testList() + { + $client = static::createClient(); + + $crawler = $client->request('GET', '/list'); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/ChillCustomFieldsBundle.php b/src/Bundle/ChillCustomFieldsBundle/ChillCustomFieldsBundle.php index 7150e5026..7bfa8572b 100644 --- a/src/Bundle/ChillCustomFieldsBundle/ChillCustomFieldsBundle.php +++ b/src/Bundle/ChillCustomFieldsBundle/ChillCustomFieldsBundle.php @@ -1,9 +1,16 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Command; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\CustomFieldsBundle\Service\CustomFieldProvider; use Doctrine\ORM\EntityManager; +use RunTimeException; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Symfony\Component\Console\Question\Question; use Symfony\Component\Validator\Validator\ValidatorInterface; -use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Exception\ParseException; -use Chill\CustomFieldsBundle\Entity\CustomField; +use Symfony\Component\Yaml\Parser; /** * Class for the command 'chill:custom_fields:populate_group' that - * Create custom fields from a yml file - * - * @author Julien Fastré - * @author Marc Ducobu + * Create custom fields from a yml file. */ class CreateFieldsOnGroupCommand extends Command { - const ARG_PATH = 'path'; - const ARG_DELETE = 'delete'; - + public const ARG_DELETE = 'delete'; + + public const ARG_PATH = 'path'; + + private $availableLanguages; + /** * @var CustomFieldProvider */ private $customFieldProvider; - + + private $customizablesEntities; + /** * @var EntityManager */ private $entityManager; - + /** * @var ValidatorInterface */ private $validator; - - private $availableLanguages; - private $customizablesEntities; - + /** * CreateFieldsOnGroupCommand constructor. * - * @param CustomFieldProvider $customFieldProvider - * @param EntityManager $entityManager - * @param ValidatorInterface $validator * @param $availableLanguages * @param $customizablesEntities */ @@ -87,19 +73,26 @@ class CreateFieldsOnGroupCommand extends Command $this->customizablesEntities = $customizablesEntities; parent::__construct(); } - + protected function configure() { $this->setName('chill:custom_fields:populate_group') ->setDescription('Create custom fields from a yml file') - ->addArgument(self::ARG_PATH, InputOption::VALUE_REQUIRED, - 'Path to description file') - ->addOption(self::ARG_DELETE, null, InputOption::VALUE_NONE, - 'If set, delete existing fields'); + ->addArgument( + self::ARG_PATH, + InputOption::VALUE_REQUIRED, + 'Path to description file' + ) + ->addOption( + self::ARG_DELETE, + null, + InputOption::VALUE_NONE, + 'If set, delete existing fields' + ); } /** - * Delete the existing custom fields for a given customFieldGroup + * Delete the existing custom fields for a given customFieldGroup. * * @param CustomFieldsGroup $customFieldsGroup : The custom field group */ @@ -111,27 +104,25 @@ class CreateFieldsOnGroupCommand extends Command $em->remove($field); } } - + /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int|null|void + * @return int|void|null */ protected function execute(InputInterface $input, OutputInterface $output) { $helper = $this->getHelperSet()->get('question'); - + $em = $this->entityManager; - + $customFieldsGroups = $em ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') ->findAll(); - + if (count($customFieldsGroups) === 0) { $output->writeln('There aren\'t any CustomFieldsGroup recorded' . ' Please create at least one.'); - } - + } + $table = new Table($output); $table ->setHeaders(array_merge( @@ -139,126 +130,130 @@ class CreateFieldsOnGroupCommand extends Command $this->availableLanguages )) ->setRows($this->_prepareRows($customFieldsGroups)) - ->render() - ; - + ->render(); + $question = new Question( - "Enter the customfieldGroup's id on which the custom fields should be added: "); + "Enter the customfieldGroup's id on which the custom fields should be added: " + ); $question->setNormalizer( - function($answer) use ($customFieldsGroups) { + function ($answer) use ($customFieldsGroups) { foreach ($customFieldsGroups as $customFieldsGroup) { - if ($answer == $customFieldsGroup->getId()) { + if ($customFieldsGroup->getId() == $answer) { return $customFieldsGroup; } } - throw new \RunTimeException('The id does not match an existing ' + + throw new RunTimeException('The id does not match an existing ' . 'CustomFieldsGroup'); } ); $customFieldsGroup = $helper->ask($input, $output, $question); - if ($input->getOption(self::ARG_DELETE)) { $this->deleteFieldsForCFGroup($customFieldsGroup); } - - $fieldsInput = $this->_parse($input->getArgument(self::ARG_PATH), - $output); - + + $fieldsInput = $this->_parse( + $input->getArgument(self::ARG_PATH), + $output + ); + $fields = $this->_addFields($customFieldsGroup, $fieldsInput, $output); } - - private function _prepareRows ($customFieldsGroups) - { - $rows = array(); - $languages = $this->availableLanguages; - //gather entitites and create an array to access them easily - $customizableEntities = array(); - foreach ($this->customizablesEntities as $entry) { - $customizableEntities[$entry['class']] = $entry['name']; - } - - array_walk($customFieldsGroups, - function(CustomFieldsGroup $customFieldGroup, $key) - use ($languages, &$rows, $customizableEntities) { - //set id and entity - $row = array( - $customFieldGroup->getId(), - $customizableEntities[$customFieldGroup->getEntity()] - ); - - foreach ($languages as $lang) { - //todo replace with service to find lang when available - $row[] = (isset($customFieldGroup->getName()[$lang])) ? - $customFieldGroup->getName()[$lang] : - 'Not available in this language'; - } - $rows[] = $row; - } - ); - - return $rows; - } - - private function _parse($path, OutputInterface $output) - { - $parser = new Parser(); - - if (!file_exists($path)) { - throw new \RunTimeException("file does not exist"); - } - - try { - $values = $parser->parse(file_get_contents($path)); - } catch (ParseException $ex) { - throw new \RunTimeException("The yaml file is not valid", 0, $ex); - } - - return $values; - } - + private function _addFields(CustomFieldsGroup $group, $values, OutputInterface $output) { - $em = $this->entityManager; $languages = $this->availableLanguages; - - foreach($values['fields'] as $slug => $field) { + + foreach ($values['fields'] as $slug => $field) { //check the cf type exists $cfType = $this->customFieldProvider->getCustomFieldByType($field['type']); - if ($cfType === NULL) { - throw new \RunTimeException('the type '.$field['type'].' ' + + if (null === $cfType) { + throw new RunTimeException('the type ' . $field['type'] . ' ' . 'does not exists'); } - + $cf = new CustomField(); $cf->setSlug($slug) ->setName($field['name']) - ->setOptions(isset($field['options']) ? $field['options'] : array() ) + ->setOptions($field['options'] ?? []) ->setOrdering($field['ordering']) ->setType($field['type']) ->setCustomFieldsGroup($group); - + //add to table - $names = array(); + $names = []; + foreach ($languages as $lang) { //todo replace with service to find lang when available $names[] = (isset($cf->getName()[$lang])) ? $cf->getName()[$lang] : 'Not available in this language'; } - + if ($this->validator->validate($cf)) { $em->persist($cf); - $output->writeln("Adding Custom Field of type " - .$cf->getType()."\t with slug ".$cf->getSlug(). - "\t and names : ".implode($names, ', ').""); + $output->writeln('Adding Custom Field of type ' + . $cf->getType() . "\t with slug " . $cf->getSlug() . + "\t and names : " . implode($names, ', ') . ''); } else { - throw new \RunTimeException("Error in field ".$slug); + throw new RunTimeException('Error in field ' . $slug); } } - + $em->flush(); } + + private function _parse($path, OutputInterface $output) + { + $parser = new Parser(); + + if (!file_exists($path)) { + throw new RunTimeException('file does not exist'); + } + + try { + $values = $parser->parse(file_get_contents($path)); + } catch (ParseException $ex) { + throw new RunTimeException('The yaml file is not valid', 0, $ex); + } + + return $values; + } + + private function _prepareRows($customFieldsGroups) + { + $rows = []; + $languages = $this->availableLanguages; + //gather entitites and create an array to access them easily + $customizableEntities = []; + + foreach ($this->customizablesEntities as $entry) { + $customizableEntities[$entry['class']] = $entry['name']; + } + + array_walk( + $customFieldsGroups, + function (CustomFieldsGroup $customFieldGroup, $key) use ($languages, &$rows, $customizableEntities) { + //set id and entity + $row = [ + $customFieldGroup->getId(), + $customizableEntities[$customFieldGroup->getEntity()], + ]; + + foreach ($languages as $lang) { + //todo replace with service to find lang when available + $row[] = (isset($customFieldGroup->getName()[$lang])) ? + $customFieldGroup->getName()[$lang] : + 'Not available in this language'; + } + $rows[] = $row; + } + ); + + return $rows; + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Controller/AdminController.php b/src/Bundle/ChillCustomFieldsBundle/Controller/AdminController.php index 86bd3c5fa..4103dc96c 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Controller/AdminController.php +++ b/src/Bundle/ChillCustomFieldsBundle/Controller/AdminController.php @@ -1,33 +1,19 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; /** * Class AdminController - * Controller for the custom fields configuration section (in admin section) - * - * @package Chill\CustomFieldsBundle\Controller + * Controller for the custom fields configuration section (in admin section). */ class AdminController extends AbstractController { @@ -35,4 +21,4 @@ class AdminController extends AbstractController { return $this->render('ChillCustomFieldsBundle:Admin:layout.html.twig'); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldController.php b/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldController.php index da6f65e5f..dff603613 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldController.php +++ b/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldController.php @@ -1,26 +1,28 @@ flush(); $this->addFlash('success', $this->get('translator') - ->trans('The custom field has been created')); + ->trans('The custom field has been created')); - return $this->redirect($this->generateUrl('customfieldsgroup_show', - array('id' => $entity->getCustomFieldsGroup()->getId()))); + return $this->redirect($this->generateUrl( + 'customfieldsgroup_show', + ['id' => $entity->getCustomFieldsGroup()->getId()] + )); } $this->addFlash('error', $this->get('translator') - ->trans("The custom field form contains errors")); + ->trans('The custom field form contains errors')); - return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', array( + return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a CustomField entity. - * - * @param CustomField $entity The entity - * @param string - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(CustomField $entity, $type) - { - $form = $this->createForm(CustomFieldType::class, $entity, array( - 'action' => $this->generateUrl('customfield_create', - array('type' => $type)), - 'method' => 'POST', - 'type' => $type, - 'group_widget' => ($entity->getCustomFieldsGroup()) ? 'hidden' :'entity' - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new CustomField entity. - * - */ - public function newAction(Request $request) - { - $entity = new CustomField(); - - //add the custom field group if defined in URL - $cfGroupId = $request->query->get('customFieldsGroup', null); - - if ($cfGroupId !== null) { - $cfGroup = $this->getDoctrine()->getManager() - ->getRepository(CustomFieldsGroup::class) - ->find($cfGroupId); - if (!$cfGroup) { - throw $this->createNotFoundException('CustomFieldsGroup with id ' - . $cfGroupId.' is not found !'); - } - $entity->setCustomFieldsGroup($cfGroup); - } - - $form = $this->createCreateForm($entity, $request->query->get('type')); - - return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a CustomField entity. - * - * @deprecated is not used since there is no link to show action - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository(CustomField::class)->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find CustomField entity.'); - } - - return $this->render('ChillCustomFieldsBundle:CustomField:show.html.twig', array( - 'entity' => $entity, )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing CustomField entity. * + * @param mixed $id */ public function editAction($id) { @@ -136,35 +70,67 @@ class CustomFieldController extends AbstractController $editForm = $this->createEditForm($entity, $entity->getType()); - return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a CustomField entity. - * - * @param CustomField $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(CustomField $entity, $type) + * Displays a form to create a new CustomField entity. + */ + public function newAction(Request $request) { - $form = $this->createForm(CustomFieldType::class, $entity, array( - 'action' => $this->generateUrl('customfield_update', array('id' => $entity->getId())), - 'method' => 'PUT', - 'type' => $type, - 'group_widget' => 'hidden' - )); + $entity = new CustomField(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + //add the custom field group if defined in URL + $cfGroupId = $request->query->get('customFieldsGroup', null); - return $form; + if (null !== $cfGroupId) { + $cfGroup = $this->getDoctrine()->getManager() + ->getRepository(CustomFieldsGroup::class) + ->find($cfGroupId); + + if (!$cfGroup) { + throw $this->createNotFoundException('CustomFieldsGroup with id ' + . $cfGroupId . ' is not found !'); + } + $entity->setCustomFieldsGroup($cfGroup); + } + + $form = $this->createCreateForm($entity, $request->query->get('type')); + + return $this->render('ChillCustomFieldsBundle:CustomField:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); } + + /** + * Finds and displays a CustomField entity. + * + * @deprecated is not used since there is no link to show action + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository(CustomField::class)->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find CustomField entity.'); + } + + return $this->render('ChillCustomFieldsBundle:CustomField:show.html.twig', [ + 'entity' => $entity, ]); + } + /** * Edits an existing CustomField entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -183,17 +149,65 @@ class CustomFieldController extends AbstractController $em->flush(); $this->addFlash('success', $this->get('translator') - ->trans("The custom field has been updated")); + ->trans('The custom field has been updated')); - return $this->redirect($this->generateUrl('customfield_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('customfield_edit', ['id' => $id])); } $this->addFlash('error', $this->get('translator') - ->trans("The custom field form contains errors")); + ->trans('The custom field form contains errors')); - return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillCustomFieldsBundle:CustomField:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a CustomField entity. + * + * @param CustomField $entity The entity + * @param string + * @param mixed $type + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(CustomField $entity, $type) + { + $form = $this->createForm(CustomFieldType::class, $entity, [ + 'action' => $this->generateUrl( + 'customfield_create', + ['type' => $type] + ), + 'method' => 'POST', + 'type' => $type, + 'group_widget' => ($entity->getCustomFieldsGroup()) ? 'hidden' : 'entity', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a CustomField entity. + * + * @param CustomField $entity The entity + * @param mixed $type + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(CustomField $entity, $type) + { + $form = $this->createForm(CustomFieldType::class, $entity, [ + 'action' => $this->generateUrl('customfield_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + 'type' => $type, + 'group_widget' => 'hidden', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php b/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php index 268b5480b..7c356f76d 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php +++ b/src/Bundle/ChillCustomFieldsBundle/Controller/CustomFieldsGroupController.php @@ -1,47 +1,47 @@ customfieldProvider = $customFieldProvider; $this->translator = $translator; } - - /** - * Lists all CustomFieldsGroup entities. - * - */ - public function indexAction() - { - $em = $this->getDoctrine()->getManager(); - - $cfGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findAll(); - $defaultGroups = $this->getDefaultGroupsId(); - - $makeDefaultFormViews = array(); - foreach ($cfGroups as $group) { - if (!in_array($group->getId(), $defaultGroups)){ - $makeDefaultFormViews[$group->getId()] = $this->createMakeDefaultForm($group)->createView(); - } - } - - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:index.html.twig', array( - 'entities' => $cfGroups, - 'default_groups' => $defaultGroups, - 'make_default_forms' => $makeDefaultFormViews - )); - } - - /** - * Get an array of CustomFieldsGroupId which are marked as default - * for their entity - * - * @return int[] - */ - private function getDefaultGroupsId() - { - $em = $this->getDoctrine()->getManager(); - - $customFieldsGroupIds = $em->createQuery('SELECT g.id FROM ' - . 'ChillCustomFieldsBundle:CustomFieldsDefaultGroup d ' - . 'JOIN d.customFieldsGroup g') - ->getResult(Query::HYDRATE_SCALAR); - - $result = array(); - foreach ($customFieldsGroupIds as $row) { - $result[] = $row['id']; - } - - return $result; - } - - /** - * create a form to make the group default - * - * @param CustomFieldsGroup $group - * @return \Symfony\Component\Form\Form - */ - private function createMakeDefaultForm(CustomFieldsGroup $group = null) - { - return $this->createFormBuilder($group, array( - 'method' => 'POST', - 'action' => $this->generateUrl('customfieldsgroup_makedefault') - )) - ->add('id', HiddenType::class) - ->add('submit', SubmitType::class, array('label' => 'Make default')) - ->getForm(); - } - /** * Creates a new CustomFieldsGroup entity. - * */ public function createAction(Request $request) { @@ -133,101 +66,24 @@ class CustomFieldsGroupController extends AbstractController $em->flush(); $this->addFlash('success', $this->translator - ->trans("The custom fields group has been created")); + ->trans('The custom fields group has been created')); - return $this->redirect($this->generateUrl('customfieldsgroup_show', array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl('customfieldsgroup_show', ['id' => $entity->getId()])); } $this->addFlash('error', $this->translator - ->trans("The custom fields group form contains errors")); + ->trans('The custom fields group form contains errors')); - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', array( + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a CustomFieldsGroup entity. - * - * @param CustomFieldsGroup $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(CustomFieldsGroup $entity) - { - $form = $this->createForm(CustomFieldsGroupType::class, $entity, array( - 'action' => $this->generateUrl('customfieldsgroup_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new CustomFieldsGroup entity. - * - */ - public function newAction() - { - $entity = new CustomFieldsGroup(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a CustomFieldsGroup entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); - } - - $options = $this->getOptionsAvailable($entity->getEntity()); - - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:show.html.twig', array( - 'entity' => $entity, - 'create_field_form' => $this->createCreateFieldForm($entity)->createView(), - 'options' => $options - )); - } - - /** - * Return an array of available key option for custom fields group - * on the given entity - * - * @param string $entity the entity to filter - */ - private function getOptionsAvailable($entity) - { - $options = $this->getParameter('chill_custom_fields.' - . 'customizables_entities'); - - foreach($options as $key => $definition) { - if ($definition['class'] == $entity) { - foreach ($definition['options'] as $key => $value) { - yield $key; - } - } - } - // [$entity->getEntity()]; + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing CustomFieldsGroup entity. * + * @param mixed $id */ public function editAction($id) { @@ -241,102 +97,42 @@ class CustomFieldsGroupController extends AbstractController $editForm = $this->createEditForm($entity); - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a CustomFieldsGroup entity. - * - * @param CustomFieldsGroup $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(CustomFieldsGroup $entity) - { - $form = $this->createForm(CustomFieldsGroupType::class, $entity, array( - 'action' => $this->generateUrl('customfieldsgroup_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - - private function createCreateFieldForm(CustomFieldsGroup $customFieldsGroup) - { - - $fieldChoices = array(); - foreach ($this->customfieldProvider->getAllFields() - as $key => $customType) { - $fieldChoices[$key] = $customType->getName(); - } - - $customfield = (new CustomField()) - ->setCustomFieldsGroup($customFieldsGroup); - - $builder = $this->get('form.factory') - ->createNamedBuilder(null, FormType::class, $customfield, array( - 'method' => 'GET', - 'action' => $this->generateUrl('customfield_new'), - 'csrf_protection' => false - )) - ->add('type', ChoiceType::class, array( - 'choices' => array_combine(array_values($fieldChoices),array_keys($fieldChoices)), - )) - ->add('customFieldsGroup', HiddenType::class) - ->add('submit', SubmitType::class); - $builder->get('customFieldsGroup') - ->addViewTransformer(new CustomFieldsGroupToIdTransformer( - $this->getDoctrine()->getManager())); - - return $builder->getForm(); - } - - /** - * Edits an existing CustomFieldsGroup entity. - * + * Lists all CustomFieldsGroup entities. */ - public function updateAction(Request $request, $id) + public function indexAction() { $em = $this->getDoctrine()->getManager(); - $entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id); + $cfGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findAll(); + $defaultGroups = $this->getDefaultGroupsId(); - if (!$entity) { - throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); + $makeDefaultFormViews = []; + + foreach ($cfGroups as $group) { + if (!in_array($group->getId(), $defaultGroups)) { + $makeDefaultFormViews[$group->getId()] = $this->createMakeDefaultForm($group)->createView(); + } } - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - $em->flush(); - - $this->addFlash('success', $this->translator - ->trans("The custom fields group has been updated")); - - return $this->redirect($this->generateUrl('customfieldsgroup_edit', array('id' => $id))); - } - - $this->addFlash('error', $this->translator - ->trans("The custom fields group form contains errors")); - - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - - )); + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:index.html.twig', [ + 'entities' => $cfGroups, + 'default_groups' => $defaultGroups, + 'make_default_forms' => $makeDefaultFormViews, + ]); } /** - * Set the CustomField Group with id $cFGroupId as default + * Set the CustomField Group with id $cFGroupId as default. */ public function makeDefaultAction(Request $request) { - $form = $this->createMakeDefaultForm(null); $form->handleRequest($request); @@ -346,16 +142,16 @@ class CustomFieldsGroupController extends AbstractController $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->findOneById($cFGroupId); - if(!$cFGroup) { + if (!$cFGroup) { throw $this - ->createNotFoundException("customFieldsGroup not found with " - . "id $cFGroupId"); + ->createNotFoundException('customFieldsGroup not found with ' + . "id {$cFGroupId}"); } $cFDefaultGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup') ->findOneByEntity($cFGroup->getEntity()); - if($cFDefaultGroup) { + if ($cFDefaultGroup) { $em->remove($cFDefaultGroup); $em->flush(); /*this is necessary, if not doctrine * will not remove old entity before adding a new one, @@ -372,11 +168,25 @@ class CustomFieldsGroupController extends AbstractController $em->flush(); $this->addFlash('success', $this->translator - ->trans("The default custom fields group has been changed")); + ->trans('The default custom fields group has been changed')); return $this->redirect($this->generateUrl('customfieldsgroup')); } + /** + * Displays a form to create a new CustomFieldsGroup entity. + */ + public function newAction() + { + $entity = new CustomFieldsGroup(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + /** * This function render the customFieldsGroup as a form. * @@ -397,33 +207,223 @@ class CustomFieldsGroupController extends AbstractController throw $this->createNotFoundException('Unable to find CustomFieldsGroups entity.'); } - $form = $this->createForm(FormTypeCustomField::class, null, array('group' => $entity)); - $form->add('submit_dump', SubmitType::class, array('label' => 'POST AND DUMP')); - $form->add('submit_render', SubmitType::class, array('label' => 'POST AND RENDER')); + $form = $this->createForm(FormTypeCustomField::class, null, ['group' => $entity]); + $form->add('submit_dump', SubmitType::class, ['label' => 'POST AND DUMP']); + $form->add('submit_render', SubmitType::class, ['label' => 'POST AND RENDER']); $form->handleRequest($request); $this->get('twig.loader') - ->addPath(__DIR__.'/../Tests/Fixtures/App/app/Resources/views/', - $namespace = 'test'); + ->addPath( + __DIR__ . '/../Tests/Fixtures/App/app/Resources/views/', + $namespace = 'test' + ); if ($form->isSubmitted()) { if ($form->get('submit_render')->isClicked()) { - return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:render_for_test.html.twig', array( + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:render_for_test.html.twig', [ 'fields' => $form->getData(), - 'customFieldsGroup' => $entity - )); + 'customFieldsGroup' => $entity, + ]); } //dump($form->getData()); //dump(json_enccode($form->getData())); } - - return $this - ->render('@test/CustomField/simple_form_render.html.twig', array( - 'form' => $form->createView() - )); + ->render('@test/CustomField/simple_form_render.html.twig', [ + 'form' => $form->createView(), + ]); + } + /** + * Finds and displays a CustomFieldsGroup entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); + } + + $options = $this->getOptionsAvailable($entity->getEntity()); + + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:show.html.twig', [ + 'entity' => $entity, + 'create_field_form' => $this->createCreateFieldForm($entity)->createView(), + 'options' => $options, + ]); + } + + /** + * Edits an existing CustomFieldsGroup entity. + * + * @param mixed $id + */ + public function updateAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.'); + } + + $editForm = $this->createEditForm($entity); + $editForm->handleRequest($request); + + if ($editForm->isValid()) { + $em->flush(); + + $this->addFlash('success', $this->translator + ->trans('The custom fields group has been updated')); + + return $this->redirect($this->generateUrl('customfieldsgroup_edit', ['id' => $id])); + } + + $this->addFlash('error', $this->translator + ->trans('The custom fields group form contains errors')); + + return $this->render('ChillCustomFieldsBundle:CustomFieldsGroup:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); + } + + private function createCreateFieldForm(CustomFieldsGroup $customFieldsGroup) + { + $fieldChoices = []; + + foreach ($this->customfieldProvider->getAllFields() + as $key => $customType) { + $fieldChoices[$key] = $customType->getName(); + } + + $customfield = (new CustomField()) + ->setCustomFieldsGroup($customFieldsGroup); + + $builder = $this->get('form.factory') + ->createNamedBuilder(null, FormType::class, $customfield, [ + 'method' => 'GET', + 'action' => $this->generateUrl('customfield_new'), + 'csrf_protection' => false, + ]) + ->add('type', ChoiceType::class, [ + 'choices' => array_combine(array_values($fieldChoices), array_keys($fieldChoices)), + ]) + ->add('customFieldsGroup', HiddenType::class) + ->add('submit', SubmitType::class); + $builder->get('customFieldsGroup') + ->addViewTransformer(new CustomFieldsGroupToIdTransformer( + $this->getDoctrine()->getManager() + )); + + return $builder->getForm(); + } + + /** + * Creates a form to create a CustomFieldsGroup entity. + * + * @param CustomFieldsGroup $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(CustomFieldsGroup $entity) + { + $form = $this->createForm(CustomFieldsGroupType::class, $entity, [ + 'action' => $this->generateUrl('customfieldsgroup_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a CustomFieldsGroup entity. + * + * @param CustomFieldsGroup $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(CustomFieldsGroup $entity) + { + $form = $this->createForm(CustomFieldsGroupType::class, $entity, [ + 'action' => $this->generateUrl('customfieldsgroup_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + ]); + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; + } + + /** + * create a form to make the group default. + * + * @param CustomFieldsGroup $group + * + * @return \Symfony\Component\Form\Form + */ + private function createMakeDefaultForm(?CustomFieldsGroup $group = null) + { + return $this->createFormBuilder($group, [ + 'method' => 'POST', + 'action' => $this->generateUrl('customfieldsgroup_makedefault'), + ]) + ->add('id', HiddenType::class) + ->add('submit', SubmitType::class, ['label' => 'Make default']) + ->getForm(); + } + + /** + * Get an array of CustomFieldsGroupId which are marked as default + * for their entity. + * + * @return int[] + */ + private function getDefaultGroupsId() + { + $em = $this->getDoctrine()->getManager(); + + $customFieldsGroupIds = $em->createQuery('SELECT g.id FROM ' + . 'ChillCustomFieldsBundle:CustomFieldsDefaultGroup d ' + . 'JOIN d.customFieldsGroup g') + ->getResult(Query::HYDRATE_SCALAR); + + $result = []; + + foreach ($customFieldsGroupIds as $row) { + $result[] = $row['id']; + } + + return $result; + } + + /** + * Return an array of available key option for custom fields group + * on the given entity. + * + * @param string $entity the entity to filter + */ + private function getOptionsAvailable($entity) + { + $options = $this->getParameter('chill_custom_fields.' + . 'customizables_entities'); + + foreach ($options as $key => $definition) { + if ($definition['class'] == $entity) { + foreach ($definition['options'] as $key => $value) { + yield $key; + } + } + } + // [$entity->getEntity()]; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/AbstractCustomField.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/AbstractCustomField.php index ddd019176..3d551cde5 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/AbstractCustomField.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/AbstractCustomField.php @@ -1,37 +1,20 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; use Chill\CustomFieldsBundle\Entity\CustomField; -/** - * - * - * @author Julien Fastré - */ abstract class AbstractCustomField implements CustomFieldInterface { public function isEmptyValue($value, CustomField $customField) { - return (empty($value) and $value !== FALSE); + return empty($value) and false !== $value; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php index eaf423b7c..2d1454080 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldChoice.php @@ -1,57 +1,44 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; use Chill\CustomFieldsBundle\Form\Type\ChoicesListType; use Chill\CustomFieldsBundle\Form\Type\ChoicesType; use Chill\CustomFieldsBundle\Form\Type\ChoiceWithOtherType; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Chill\CustomFieldsBundle\Entity\CustomField; -use Symfony\Component\HttpFoundation\RequestStack; -use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; -use Symfony\Bridge\Twig\TwigEngine; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use LogicException; +use Symfony\Bridge\Twig\TwigEngine; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Contracts\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - * @author Marc Ducobu - */ +use function LogicException; + class CustomFieldChoice extends AbstractCustomField { - const ALLOW_OTHER = 'other'; - const OTHER_VALUE_LABEL = 'otherValueLabel'; - const MULTIPLE = 'multiple'; - const EXPANDED = 'expanded'; - const CHOICES = 'choices'; + public const ALLOW_OTHER = 'other'; + + public const CHOICES = 'choices'; + + public const EXPANDED = 'expanded'; + + public const MULTIPLE = 'multiple'; + + public const OTHER_VALUE_LABEL = 'otherValueLabel'; private $defaultLocales; /** - * * @var TwigEngine */ private $templating; @@ -60,48 +47,50 @@ class CustomFieldChoice extends AbstractCustomField * @var TranslatableStringHelper Helper that find the string in current locale from an array of translation */ private $translatableStringHelper; - + /** * CustomFieldChoice constructor. - * - * @param TranslatorInterface $translator - * @param TwigEngine $templating - * @param TranslatableStringHelper $translatableStringHelper */ public function __construct( TranslatorInterface $translator, TwigEngine $templating, - TranslatableStringHelper $translatableStringHelper) - { + TranslatableStringHelper $translatableStringHelper + ) { $this->defaultLocales = $translator->getFallbackLocales(); $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; } + public function allowOtherChoice(CustomField $cf) + { + return $cf->getOptions()[self::ALLOW_OTHER]; + } + public function buildForm(FormBuilderInterface $builder, CustomField $customField) { //prepare choices - $choices = array(); + $choices = []; $customFieldOptions = $customField->getOptions(); - foreach($customFieldOptions[self::CHOICES] as $persistedChoices) { - if ($persistedChoices['active']){ + foreach ($customFieldOptions[self::CHOICES] as $persistedChoices) { + if ($persistedChoices['active']) { $choices[$persistedChoices['slug']] = $this->translatableStringHelper->localize($persistedChoices['name']); } } //prepare $options - $options = array( + $options = [ 'multiple' => $customFieldOptions[self::MULTIPLE], - 'choices' => array_combine(array_values($choices),array_keys($choices)), + 'choices' => array_combine(array_values($choices), array_keys($choices)), 'required' => $customField->isRequired(), - 'label' => $this->translatableStringHelper->localize($customField->getName()) - ); + 'label' => $this->translatableStringHelper->localize($customField->getName()), + ]; //if allow_other = true - if ($customFieldOptions[self::ALLOW_OTHER] == true) { + if (true == $customFieldOptions[self::ALLOW_OTHER]) { $otherValueLabel = null; - if(array_key_exists(self::OTHER_VALUE_LABEL, $customFieldOptions)) { + + if (array_key_exists(self::OTHER_VALUE_LABEL, $customFieldOptions)) { $otherValueLabel = $this->translatableStringHelper->localize( $customFieldOptions[self::OTHER_VALUE_LABEL] ); @@ -113,10 +102,10 @@ class CustomFieldChoice extends AbstractCustomField $customField->getSlug(), ChoiceWithOtherType::class, $options, - array('other_value_label'=> $otherValueLabel) - ) - ->addModelTransformer(new CustomFieldDataTransformer($this, $customField))); - + ['other_value_label' => $otherValueLabel] + ) + ->addModelTransformer(new CustomFieldDataTransformer($this, $customField)) + ); } else { //if allow_other = false //we add the 'expanded' to options $options['expanded'] = $customFieldOptions[self::EXPANDED]; @@ -131,41 +120,41 @@ class CustomFieldChoice extends AbstractCustomField public function buildOptionsForm(FormBuilderInterface $builder) { $builder - ->add(self::MULTIPLE, ChoiceType::class, array( + ->add(self::MULTIPLE, ChoiceType::class, [ 'expanded' => true, 'multiple' => false, - 'choices' => array( + 'choices' => [ 'Multiple' => '1', - 'Unique' => '0'), + 'Unique' => '0', ], 'empty_data' => '0', - 'label' => 'Multiplicity' - )) - ->add(self::EXPANDED, ChoiceType::class, array( + 'label' => 'Multiplicity', + ]) + ->add(self::EXPANDED, ChoiceType::class, [ 'expanded' => true, 'multiple' => false, - 'choices' => array( + 'choices' => [ 'Expanded' => '1', - 'Non expanded' => '0'), + 'Non expanded' => '0', ], 'empty_data' => '0', - 'label' => 'Choice display' - )) - ->add(self::ALLOW_OTHER, ChoiceType::class, array( + 'label' => 'Choice display', + ]) + ->add(self::ALLOW_OTHER, ChoiceType::class, [ 'label' => 'Allow other', - 'choices' => array( + 'choices' => [ 'No' => '0', - 'Yes' => '1'), + 'Yes' => '1', ], 'empty_data' => '0', 'expanded' => true, - 'multiple' => false - )) - ->add(self::OTHER_VALUE_LABEL, TranslatableStringFormType::class, array( - 'label' => 'Other value label (empty if use by default)')) - ->add(self::CHOICES, ChoicesType::class, array( + 'multiple' => false, + ]) + ->add(self::OTHER_VALUE_LABEL, TranslatableStringFormType::class, [ + 'label' => 'Other value label (empty if use by default)', ]) + ->add(self::CHOICES, ChoicesType::class, [ 'entry_type' => ChoicesListType::class, - 'allow_add' => true - )); + 'allow_add' => true, + ]); - return $builder; + return $builder; } public function deserialize($serialized, CustomField $customField) @@ -175,12 +164,183 @@ class CustomFieldChoice extends AbstractCustomField if ($options[self::MULTIPLE]) { return $this->deserializeToMultiple($serialized, $options[self::ALLOW_OTHER]); - } else { - return $this->deserializeToUnique($serialized, $options[self::ALLOW_OTHER]); } + + return $this->deserializeToUnique($serialized, $options[self::ALLOW_OTHER]); + return $serialized; } + public function extractOtherValue(CustomField $cf, ?array $data = null) + { + return $data['_other']; + } + + public function getChoices(CustomField $cf) + { + if ($cf->getOptions()[self::MULTIPLE]) { + $choices = []; + + foreach ($cf->getOptions()[self::CHOICES] as $choice) { + if (false === $choices['active']) { + continue; + } + $choices[$choice['slug']] = $this->translatableStringHelper + ->localize($choice['name']); + } + + if ($this->allowOtherChoice($cf)) { + $labels = $cf->getOptions()[self::OTHER_VALUE_LABEL]; + + if (!is_array($labels) or count($labels) === 0) { + $labels['back'] = 'other value'; + } + $choices['_other'] = $this->translatableStringHelper + ->localize($labels); + } + + return $choices; + } + + return [ + $cf->getSlug() => $this->translatableStringHelper->localize($cf->getName()), + ]; + } + + public function getName() + { + return 'Choices'; + } + + /** + * Return true if the choice given in $choiceSlug is checked inside $data. + * + * Used in list exports. + * + * @param string $choiceSlug the slug of the choice we want to know if it was checked + * @param array|string $data the data of the field + * + * @return bool + */ + public function isChecked(CustomField $cf, $choiceSlug, $data) + { + if (null === $data) { + return false; + } + + if ($cf->getOptions()[self::MULTIPLE]) { + if ($cf->getOptions()[self::ALLOW_OTHER]) { + return \in_array($choiceSlug, $this->deserialize($data, $cf)['_choices']); + } + + return \in_array($choiceSlug, $this->deserialize($data, $cf)); + } + + if ($cf->getOptions()[self::ALLOW_OTHER]) { + return $this->deserialize($data, $cf)['_choices'] === $choiceSlug; + } + + return $this->deserialize($data, $cf) === $choiceSlug; + } + + public function isEmptyValue($value, CustomField $customField) + { + if (null === $value) { + return true; + } + + // if multiple choice OR multiple/single choice with other + if (is_array($value)) { + // if allow other + if (array_key_exists('_choices', $value)) { + if (null === $value['_choices']) { + return true; + } + + return empty($value['_choices']); + } // we do not have 'allow other' + + if (count($value) === 1) { + return empty($value[0]); + } + + return empty($value); + } + + return empty($value); + + throw LogicException('This case is not expected.'); + } + + public function isMultiple(CustomField $cf) + { + return $cf->getOptions()[self::MULTIPLE]; + } + + /** + * @internal this function is able to receive data whichever is the value of "other", "multiple" + * + * @param mixed $value + * @param mixed $documentType + * + * @return string html representation + */ + public function render($value, CustomField $customField, $documentType = 'html') + { + //extract the data. They are under a _choice key if they are stored with allow_other + $data = (isset($value['_choices'])) ? $value['_choices'] : $value; + $selected = (is_array($data)) ? $data : [$data]; + $choices = $customField->getOptions()[self::CHOICES]; + + if (in_array('_other', $selected)) { + $choices[] = ['name' => $value['_other'], 'slug' => '_other']; + } + + $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.html.twig'; + + if ('csv' == $documentType) { + $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.csv.twig'; + } + + return $this->templating + ->render( + $template, + [ + 'choices' => $choices, + 'selected' => $selected, + 'multiple' => $customField->getOptions()[self::MULTIPLE], + 'expanded' => $customField->getOptions()[self::EXPANDED], + 'locales' => $this->defaultLocales, + ] + ); + } + + public function serialize($value, CustomField $customField) + { + return $value; + } + + /** + * deserialized the data from the database to a multiple + * field. + * + * @param mixed $serialized + * @param bool $allowOther + */ + private function deserializeToMultiple($serialized, $allowOther) + { + $value = $this->guessValue($serialized); + + // set in an array : we want a multiple + $fixedValue = is_array($value) ? $value : [$value]; + + if ($allowOther) { + return $this->deserializeWithAllowOther($serialized, $fixedValue); + } + + return $fixedValue; + } + private function deserializeToUnique($serialized, $allowOther) { $value = $this->guessValue($serialized); @@ -194,40 +354,19 @@ class CustomFieldChoice extends AbstractCustomField if ($allowOther) { return $this->deserializeWithAllowOther($serialized, $fixedValue); - } else { - return $fixedValue; } - } - /** - * deserialized the data from the database to a multiple - * field - * - * @param mixed $serialized - * @param boolean $allowOther - */ - private function deserializeToMultiple($serialized, $allowOther) - { - $value = $this->guessValue($serialized); - - // set in an array : we want a multiple - $fixedValue = is_array($value) ? $value : array($value); - - if ($allowOther) { - return $this->deserializeWithAllowOther($serialized, $fixedValue); - } else { - return $fixedValue; - } + return $fixedValue; } private function deserializeWithAllowOther($serialized, $value) { - $existingOther = isset($serialized['_other']) ? $serialized['_other'] : ''; + $existingOther = $serialized['_other'] ?? ''; - return array( + return [ '_other' => $existingOther, - '_choices' => $value - ); + '_choices' => $value, + ]; } /** @@ -237,177 +376,27 @@ class CustomFieldChoice extends AbstractCustomField * **is not** the content of the _other field, but the `_other` string. * * @param array|string $value + * + * @throws LogicException if the case is not covered by this + * * @return mixed - * @throws \LogicException if the case is not covered by this */ private function guessValue($value) { - if ($value === NULL) { - return NULL; + if (null === $value) { + return null; } if (!is_array($value)) { return $value; - } else { - // we have a field with "allow other" - if (array_key_exists('_choices', $value)) { - return $value['_choices']; - } else { - // we have a field with "multiple" - return $value; - } } - - throw \LogicException("This case is not expected."); - } - - public function getName() - { - return 'Choices'; - } - - public function isEmptyValue($value, CustomField $customField) - { - if ($value === NULL) { - return true; + // we have a field with "allow other" + if (array_key_exists('_choices', $value)) { + return $value['_choices']; } - - // if multiple choice OR multiple/single choice with other - if (is_array($value)) - { - // if allow other - if (array_key_exists('_choices', $value)) { - if ($value['_choices'] === NULL) { - return true; - } - return empty($value['_choices']); - } else { // we do not have 'allow other' - if (count($value) === 1){ - return empty($value[0]); - } else { - return empty($value); - } - } - } else { - return empty($value); - } - - throw \LogicException("This case is not expected."); - } - - /** - * - * @internal this function is able to receive data whichever is the value of "other", "multiple" - * @param mixed $value - * @param CustomField $customField - * @return string html representation - */ - public function render($value, CustomField $customField, $documentType = 'html') - { - //extract the data. They are under a _choice key if they are stored with allow_other - $data = (isset($value['_choices'])) ? $value['_choices'] : $value; - $selected = (is_array($data)) ? $data : array($data); - $choices = $customField->getOptions()[self::CHOICES]; - - if (in_array('_other', $selected)){ - $choices[] = array('name' => $value['_other'], 'slug' => '_other'); - } - - $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.html.twig'; - if($documentType == 'csv') { - $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice.csv.twig'; - } - - return $this->templating - ->render($template, - array( - 'choices' => $choices, - 'selected' => $selected, - 'multiple' => $customField->getOptions()[self::MULTIPLE], - 'expanded' => $customField->getOptions()[self::EXPANDED], - 'locales' => $this->defaultLocales - ) - ); - } - - public function serialize($value, CustomField $customField) - { + // we have a field with "multiple" return $value; - } - - public function getChoices(CustomField $cf) - { - if ($cf->getOptions()[self::MULTIPLE]) { - $choices = array(); - - foreach ($cf->getOptions()[self::CHOICES] as $choice) { - if ($choices['active'] === false) { - continue; - } - $choices[$choice["slug"]] = $this->translatableStringHelper - ->localize($choice["name"]); - } - - if ($this->allowOtherChoice($cf)) { - $labels = $cf->getOptions()[self::OTHER_VALUE_LABEL]; - if (!is_array($labels) or count($labels) === 0) { - $labels['back'] = 'other value'; - } - $choices['_other'] = $this->translatableStringHelper - ->localize($labels); - } - - return $choices; - } else { - return [ - $cf->getSlug() => $this->translatableStringHelper->localize($cf->getName()) - ]; - } - } - - /** - * Return true if the choice given in $choiceSlug is checked inside $data. - * - * Used in list exports. - * - * @param CustomField $cf - * @param string $choiceSlug the slug of the choice we want to know if it was checked - * @param array|string $data the data of the field - * @return boolean - */ - public function isChecked(CustomField $cf, $choiceSlug, $data) - { - if ($data === null) { - return false; - } - - if ($cf->getOptions()[self::MULTIPLE]) { - if ($cf->getOptions()[self::ALLOW_OTHER]) { - return \in_array($choiceSlug, $this->deserialize($data, $cf)['_choices']); - } else { - return \in_array($choiceSlug, $this->deserialize($data, $cf)); - } - } else { - if ($cf->getOptions()[self::ALLOW_OTHER]) { - return $this->deserialize($data, $cf)['_choices'] === $choiceSlug; - } else { - return $this->deserialize($data, $cf) === $choiceSlug; - } - } - } - - public function isMultiple(CustomField $cf) - { - return $cf->getOptions()[self::MULTIPLE]; - } - - public function allowOtherChoice(CustomField $cf) - { - return $cf->getOptions()[self::ALLOW_OTHER]; - } - - public function extractOtherValue(CustomField $cf, array $data = null) - { - return $data['_other']; + + throw LogicException('This case is not expected.'); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php index b5ebf7554..040b54be0 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldDate.php @@ -1,196 +1,112 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; use Chill\CustomFieldsBundle\Entity\CustomField; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; -use Symfony\Component\Validator\Constraints\LessThanOrEqual; -use Symfony\Bundle\TwigBundle\TwigEngine; -use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use DateTime; +use Exception; +use Symfony\Bundle\TwigBundle\TwigEngine; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; /** * Create a custom date number. - * + * * The date may have a min and max value. - * + * * The date is stored as an unix timestamp. - * - * @author Julien Fastré */ class CustomFieldDate extends AbstractCustomField { + public const DATE_FORMAT = DateTime::RFC3339; + + public const FORMAT = 'format'; + + public const MAX = 'max'; + /** - * key for the minimal value of the field + * key for the minimal value of the field. */ - const MIN = 'min'; - const MAX = 'max'; - const FORMAT = 'format'; - const DATE_FORMAT = \DateTime::RFC3339; - + public const MIN = 'min'; + /** - * * @var TwigEngine */ - private $templating = NULL; - + private $templating; + /** - * * @var TranslatableStringHelper */ - private $translatableStringHelper = NULL; - + private $translatableStringHelper; + public function __construct(TwigEngine $templating, TranslatableStringHelper $translatableStringHelper) { $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; } - + public function buildForm(FormBuilderInterface $builder, CustomField $customField) { $fieldOptions = $this->prepareFieldOptions($customField); - + $builder->add( $builder ->create( - $customField->getSlug(), - ChillDateType::class, - $fieldOptions) + $customField->getSlug(), + ChillDateType::class, + $fieldOptions + ) ->addModelTransformer( new CustomFieldDataTransformer($this, $customField) - ) - ) - ; - } - - /** - * prepare the options'form field - * - * @param CustomField $customField - * @param string $type - * @return mixed[] - */ - private function prepareFieldOptions(CustomField $customField) - { - $options = $customField->getOptions(); - - /** - * @var mixed[] the formField options - */ - $fieldOptions = array(); - - // add required - $fieldOptions['required'] = False; - - //add label - $fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName()); - - // add constraints if required - if ($options[self::MIN] !== NULL) { - $fieldOptions['constraints'][] = new Callback( - function($timestamp, ExecutionContextInterface $context) use ($options) { - if ($timestamp === null) { - return; - } - - $value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); - $after = new \DateTime($options[self::MIN]); - - if ($value < $after) { - $context - ->buildViolation('This date must be after or equal to %date%', [ - '%date%' => $after->format('d-m-Y') - ]) - ->addViolation(); - } - } - ); - } - if ($options[self::MAX] !== NULL) { - $fieldOptions['constraints'][] = new Callback( - function($timestamp, ExecutionContextInterface $context) use ($options) { - if ($timestamp === null) { - return; - } - - $value = \DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); - $before = new \DateTime($options[self::MAX]); - - if ($value > $before) { - $context - ->buildViolation('This date must be before or equal to %date%', [ - '%date%' => $before->format('d-m-Y') - ]) - ->addViolation(); - } - } - ); - } - - return $fieldOptions; + ) + ); } public function buildOptionsForm(FormBuilderInterface $builder) { - $validatorFunction = function($value, ExecutionContextInterface $context) { + $validatorFunction = function ($value, ExecutionContextInterface $context) { try { - $date = new \DateTime($value); - } catch (\Exception $e) { + $date = new DateTime($value); + } catch (Exception $e) { $context->buildViolation('The expression "%expression%" is invalid', [ - '%expression%' => $value + '%expression%' => $value, ]) - ->addViolation() - ; + ->addViolation(); } }; - + return $builder - ->add(self::MIN, TextType::class, array( - 'label' => 'Greater or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', - 'required' => false, - 'constraints' => [ new Callback($validatorFunction) ] - )) - ->add(self::MAX, TextType::class, array( - 'label' => 'Lesser or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', - 'required' => false, - 'constraints' => [ new Callback($validatorFunction) ] - )) - ->add(self::FORMAT, ChoiceType::class, [ - 'label' => 'Format', - 'choices' => [ - 'medium' => 'medium', - 'long' => 'long', - 'short' => 'short' - ] - ]) - ; - + ->add(self::MIN, TextType::class, [ + 'label' => 'Greater or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', + 'required' => false, + 'constraints' => [new Callback($validatorFunction)], + ]) + ->add(self::MAX, TextType::class, [ + 'label' => 'Lesser or equal than (expression like 1 day ago, 2 years ago, +1 month, today, tomorrow, or date with format YYYY-mm-dd)', + 'required' => false, + 'constraints' => [new Callback($validatorFunction)], + ]) + ->add(self::FORMAT, ChoiceType::class, [ + 'label' => 'Format', + 'choices' => [ + 'medium' => 'medium', + 'long' => 'long', + 'short' => 'short', + ], + ]); } public function deserialize($serialized, CustomField $customField) @@ -198,8 +114,8 @@ class CustomFieldDate extends AbstractCustomField if (empty($serialized)) { return null; } - - return \DateTime::createFromFormat(self::DATE_FORMAT, $serialized); + + return DateTime::createFromFormat(self::DATE_FORMAT, $serialized); } public function getName() @@ -212,30 +128,97 @@ class CustomFieldDate extends AbstractCustomField switch ($documentType) { case 'csv': $date = $this->deserialize($value, $customField); - if (NULL === $date) { + + if (null === $date) { return null; } - - return $date->format('Y-m-d'); + + return $date->format('Y-m-d'); + default: $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:date.' - .$documentType.'.twig'; + . $documentType . '.twig'; return $this->templating - ->render($template, array( + ->render($template, [ 'value' => $this->deserialize($value, $customField), - 'format' => $customField->getOptions()[self::FORMAT] - )); + 'format' => $customField->getOptions()[self::FORMAT], + ]); } } public function serialize($date, CustomField $customField) { - if ($date === null) { + if (null === $date) { return null; } - + return $date->format(self::DATE_FORMAT); } + /** + * prepare the options'form field. + * + * @return mixed[] + */ + private function prepareFieldOptions(CustomField $customField) + { + $options = $customField->getOptions(); + + /** + * @var mixed[] the formField options + */ + $fieldOptions = []; + + // add required + $fieldOptions['required'] = false; + + //add label + $fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName()); + + // add constraints if required + if (null !== $options[self::MIN]) { + $fieldOptions['constraints'][] = new Callback( + function ($timestamp, ExecutionContextInterface $context) use ($options) { + if (null === $timestamp) { + return; + } + + $value = DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); + $after = new DateTime($options[self::MIN]); + + if ($value < $after) { + $context + ->buildViolation('This date must be after or equal to %date%', [ + '%date%' => $after->format('d-m-Y'), + ]) + ->addViolation(); + } + } + ); + } + + if (null !== $options[self::MAX]) { + $fieldOptions['constraints'][] = new Callback( + function ($timestamp, ExecutionContextInterface $context) use ($options) { + if (null === $timestamp) { + return; + } + + $value = DateTime::createFromFormat(self::DATE_FORMAT, $timestamp); + $before = new DateTime($options[self::MAX]); + + if ($value > $before) { + $context + ->buildViolation('This date must be before or equal to %date%', [ + '%date%' => $before->format('d-m-Y'), + ]) + ->addViolation(); + } + } + ); + } + + return $fieldOptions; + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldInterface.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldInterface.php index ce341142d..1c94d439b 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldInterface.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldInterface.php @@ -1,69 +1,74 @@ - */ interface CustomFieldInterface { - /** - * Return a form type to edit the custom field. This form is shown to the - * user. + * Return a form type to edit the custom field. This form is shown to the + * user. * * @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField + * * @return \Symfony\Component\Form\FormTypeInterface the form type */ public function buildForm(FormBuilderInterface $builder, CustomField $customField); /** - * Transform the value into a format that can be stored in DB - * - * @param mixed $value - * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField + * Return a formType which allow to edit option for the custom type. + * This FormType is shown in admin. + * + * @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder + * + * @return \Symfony\Component\Form\FormTypeInterface|null the form type */ - public function serialize($value, CustomField $customField); + public function buildOptionsForm(FormBuilderInterface $builder); /** * Transform the representation of the value, stored in db, into the * value which may be used in the process. - * - * @param mixed $value + * * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField + * @param mixed $serialized */ public function deserialize($serialized, CustomField $customField); + public function getName(); + + /** + * Return if the value can be considered as empty. + * + * @param mixed $value the value passed throug the deserialize function + */ + public function isEmptyValue($value, CustomField $customField); + /** * Return a repsentation of the value of the CustomField. - * + * * @param mixed $value the raw value, **not deserialized** (= as stored in the db) * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField + * @param mixed $documentType + * * @return string an html representation of the value */ public function render($value, CustomField $customField, $documentType = 'html'); - - public function getName(); - + /** - * Return a formType which allow to edit option for the custom type. - * This FormType is shown in admin - * - * @param \Chill\CustomFieldsBundle\CustomField\FormBuilderInterface $builder - * @return \Symfony\Component\Form\FormTypeInterface|null the form type + * Transform the value into a format that can be stored in DB. + * + * @param mixed $value + * @param \Chill\CustomFieldsBundle\CustomField\CustomField $customField */ - public function buildOptionsForm(FormBuilderInterface $builder); - - /** - * Return if the value can be considered as empty - * - * @param mixed $value the value passed throug the deserialize function - * @param CustomField $customField - */ - public function isEmptyValue($value, CustomField $customField); + public function serialize($value, CustomField $customField); } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php index feca7e351..21fbcac56 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldLongChoice.php @@ -1,64 +1,49 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; -use Symfony\Component\Form\FormBuilderInterface; use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; +use Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository; use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; -use Symfony\Bridge\Twig\TwigEngine; use Chill\MainBundle\Form\Type\Select2ChoiceType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use LogicException; +use Symfony\Bridge\Twig\TwigEngine; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - * @author Julien Fastré - */ class CustomFieldLongChoice extends AbstractCustomField { + public const KEY = 'key'; + /** - * * @var OptionRepository */ private $optionRepository; - /** - * - * @var TranslatableStringHelper - */ - private $translatableStringHelper; - /** * @var TwigEngine */ private $templating; - const KEY = 'key'; + /** + * @var TranslatableStringHelper + */ + private $translatableStringHelper; - public function __construct(OptionRepository $optionRepository, + public function __construct( + OptionRepository $optionRepository, TranslatableStringHelper $translatableStringHelper, - TwigEngine $twigEngine) - { + TwigEngine $twigEngine + ) { $this->optionRepository = $optionRepository; $this->translatableStringHelper = $translatableStringHelper; $this->templating = $twigEngine; @@ -67,62 +52,64 @@ class CustomFieldLongChoice extends AbstractCustomField public function buildForm(FormBuilderInterface $builder, CustomField $customField) { $options = $customField->getOptions(); - $entries = $this->optionRepository->findFilteredByKey($options[self::KEY], - false, true); + $entries = $this->optionRepository->findFilteredByKey( + $options[self::KEY], + false, + true + ); //create a local copy of translatable string helper $translatableStringHelper = $this->translatableStringHelper; - $builder->add($customField->getSlug(), Select2ChoiceType::class, array( + $builder->add($customField->getSlug(), Select2ChoiceType::class, [ 'choices' => $entries, - 'choice_label' => function(Option $option) use ($translatableStringHelper) { + 'choice_label' => function (Option $option) use ($translatableStringHelper) { return $translatableStringHelper->localize($option->getText()); }, - 'choice_value' => function ($key) use ($entries) { - if ($key === NULL) { + 'choice_value' => function ($key) { + if (null === $key) { return null; } + return $key->getId(); }, 'multiple' => false, 'expanded' => false, 'required' => $customField->isRequired(), 'placeholder' => 'Choose a value', - 'group_by' => function(Option $option) use ($translatableStringHelper) { + 'group_by' => function (Option $option) use ($translatableStringHelper) { if ($option->hasParent()) { return $translatableStringHelper->localize($option->getParent()->getText()); - } else { - return $translatableStringHelper->localize($option->getText()); } - }, - 'label' => $translatableStringHelper->localize($customField->getName()) - )); - $builder->get($customField->getSlug()) - ->addModelTransformer(new CustomFieldDataTransformer($this, $customField)); + return $translatableStringHelper->localize($option->getText()); + }, + 'label' => $translatableStringHelper->localize($customField->getName()), + ]); + $builder->get($customField->getSlug()) + ->addModelTransformer(new CustomFieldDataTransformer($this, $customField)); } public function buildOptionsForm(FormBuilderInterface $builder) { //create a selector between different keys $keys = $this->optionRepository->getKeys(); - $choices = array(); + $choices = []; + foreach ($keys as $key) { $choices[$key] = $key; } - return $builder->add(self::KEY, ChoiceType::class, array( - 'choices' => array_combine(array_values($choices),array_keys($choices)), + return $builder->add(self::KEY, ChoiceType::class, [ + 'choices' => array_combine(array_values($choices), array_keys($choices)), 'label' => 'Options key', - )); - + ]); } - public function deserialize($serialized, \Chill\CustomFieldsBundle\Entity\CustomField $customField) + public function deserialize($serialized, CustomField $customField) { - if ($serialized === NULL) { - return NULL; + if (null === $serialized) { + return null; } - return $this->optionRepository->find($serialized); } @@ -131,32 +118,31 @@ class CustomFieldLongChoice extends AbstractCustomField return 'Long choice field'; } - public function render($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField, $documentType = 'html') + public function render($value, CustomField $customField, $documentType = 'html') { $option = $this->deserialize($value, $customField); $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:choice_long.' - .$documentType.'.twig'; + . $documentType . '.twig'; return $this->templating - ->render($template, array( - 'values' => $option === NULL ? array() : array($option) - )); + ->render($template, [ + 'values' => null === $option ? [] : [$option], + ]); } - public function serialize($value, \Chill\CustomFieldsBundle\Entity\CustomField $customField) + public function serialize($value, CustomField $customField) { - if ($value === NULL) { - return NULL; + if (null === $value) { + return null; } if (!$value instanceof Option) { - throw new \LogicException('the value should be an instance of ' + throw new LogicException('the value should be an instance of ' . 'Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option, ' - . is_object($value) ? get_class($value) : gettype($value).' given'); + . is_object($value) ? get_class($value) : gettype($value) . ' given'); } // we place the id in array, to allow in the future multiple select return $value->getId(); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php index caf892c0e..1e9029dcd 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldNumber.php @@ -1,69 +1,51 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bundle\TwigBundle\TwigEngine; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\LessThanOrEqual; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bundle\TwigBundle\TwigEngine; -use Symfony\Component\Form\Extension\Core\Type\NumberType; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; -use Symfony\Component\Form\Extension\Core\Type\TextType; - -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; -use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\MainBundle\Templating\TranslatableStringHelper; /** * Create a custom field number. * * This number may have a min and max value, and a precision. - * - * @author Julien Fastré - * @author Marc Ducobu */ class CustomFieldNumber extends AbstractCustomField { - /** - * key for the minimal value of the field - */ - const MIN = 'min'; - const MAX = 'max'; - const SCALE = 'scale'; - const POST_TEXT = 'post_text'; + public const MAX = 'max'; + + /** + * key for the minimal value of the field. + */ + public const MIN = 'min'; + + public const POST_TEXT = 'post_text'; + + public const SCALE = 'scale'; /** - * * @var TwigEngine */ - private $templating = NULL; + private $templating; /** - * * @var TranslatableStringHelper */ - private $translatableStringHelper = NULL; + private $translatableStringHelper; public function __construct(TwigEngine $templating, TranslatableStringHelper $translatableStringHelper) { @@ -76,82 +58,38 @@ class CustomFieldNumber extends AbstractCustomField $options = $customField->getOptions(); //select the type depending to the SCALE - $type = ($options[self::SCALE] === 0 or $options[self::SCALE] === NULL)? + $type = (0 === $options[self::SCALE] or null === $options[self::SCALE]) ? IntegerType::class : NumberType::class; - //'integer' : 'number'; + //'integer' : 'number'; $fieldOptions = $this->prepareFieldOptions($customField, $type); $builder->add($customField->getSlug(), $type, $fieldOptions); } - /** - * prepare the options'form field - * - * @param CustomField $customField - * @param string $type - * @return mixed[] - */ - private function prepareFieldOptions(CustomField $customField, $type) - { - $options = $customField->getOptions(); - - /** - * @var mixed[] the formField options - */ - $fieldOptions = array(); - - // add required - $fieldOptions['required'] = False; - - //add label - $fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName()); - - // add constraints if required - if ($options[self::MIN] !== NULL) { - $fieldOptions['constraints'][] = new GreaterThanOrEqual(array('value' => $options[self::MIN])); - } - if ($options[self::MAX] !== NULL) { - $fieldOptions['constraints'][] = new LessThanOrEqual(array('value' => $options[self::MAX])); - } - - // add precision to options if required - if ($type === 'number') { - $fieldOptions['scale'] = $options[self::SCALE]; - } - - if (!empty($options[self::POST_TEXT])) { - $fieldOptions['post_text'] = $options[self::POST_TEXT]; - } - - return $fieldOptions; - } - public function buildOptionsForm(FormBuilderInterface $builder) { return $builder - ->add(self::MIN, NumberType::class, array( - 'scale' => 2, - 'label' => 'Greater or equal than', - 'required' => false - )) - ->add(self::MAX, NumberType::class, array( - 'scale' => 2, - 'label' => 'Lesser or equal than', - 'required' => false - )) - ->add(self::SCALE, IntegerType::class, array( - 'scale' => 0, - 'label' => 'Precision', - 'constraints' => array( - new GreaterThanOrEqual(array('value' => 0)) - ) - )) - ->add(self::POST_TEXT, TextType::class, array( - 'label' => 'Text after the field' - )) - ; - + ->add(self::MIN, NumberType::class, [ + 'scale' => 2, + 'label' => 'Greater or equal than', + 'required' => false, + ]) + ->add(self::MAX, NumberType::class, [ + 'scale' => 2, + 'label' => 'Lesser or equal than', + 'required' => false, + ]) + ->add(self::SCALE, IntegerType::class, [ + 'scale' => 0, + 'label' => 'Precision', + 'constraints' => [ + new GreaterThanOrEqual(['value' => 0]), + ], + ]) + ->add(self::POST_TEXT, TextType::class, [ + 'label' => 'Text after the field', + ]); } public function deserialize($serialized, CustomField $customField) @@ -167,15 +105,15 @@ class CustomFieldNumber extends AbstractCustomField public function render($value, CustomField $customField, $documentType = 'html') { $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:number.' - .$documentType.'.twig'; + . $documentType . '.twig'; $options = $customField->getOptions(); return $this->templating - ->render($template, array( + ->render($template, [ 'number' => $value, 'scale' => $options[self::SCALE], - 'post' => $options[self::POST_TEXT] - )); + 'post' => $options[self::POST_TEXT], + ]); } public function serialize($value, CustomField $customField) @@ -183,4 +121,46 @@ class CustomFieldNumber extends AbstractCustomField return $value; } + /** + * prepare the options'form field. + * + * @param string $type + * + * @return mixed[] + */ + private function prepareFieldOptions(CustomField $customField, $type) + { + $options = $customField->getOptions(); + + /** + * @var mixed[] the formField options + */ + $fieldOptions = []; + + // add required + $fieldOptions['required'] = false; + + //add label + $fieldOptions['label'] = $this->translatableStringHelper->localize($customField->getName()); + + // add constraints if required + if (null !== $options[self::MIN]) { + $fieldOptions['constraints'][] = new GreaterThanOrEqual(['value' => $options[self::MIN]]); + } + + if (null !== $options[self::MAX]) { + $fieldOptions['constraints'][] = new LessThanOrEqual(['value' => $options[self::MAX]]); + } + + // add precision to options if required + if ('number' === $type) { + $fieldOptions['scale'] = $options[self::SCALE]; + } + + if (!empty($options[self::POST_TEXT])) { + $fieldOptions['post_text'] = $options[self::POST_TEXT]; + } + + return $fieldOptions; + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php index abd6e7911..ea41f8f6c 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldText.php @@ -1,49 +1,33 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bundle\TwigBundle\TwigEngine; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bundle\TwigBundle\TwigEngine; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Form\Extension\Core\Type\TextareaType; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; -use Symfony\Component\Form\Extension\Core\Type\TextType; -/** - * @author Julien Fastré - * @author Marc Ducobu - */ class CustomFieldText extends AbstractCustomField { + public const MAX_LENGTH = 'maxLength'; + + public const MULTIPLE_CF_INLINE = 'multipleCFInline'; private $requestStack; /** - * * @var TwigEngine */ private $templating; @@ -53,62 +37,57 @@ class CustomFieldText extends AbstractCustomField */ private $translatableStringHelper; - - public function __construct(RequestStack $requestStack, TwigEngine $templating, - TranslatableStringHelper $translatableStringHelper) - { + public function __construct( + RequestStack $requestStack, + TwigEngine $templating, + TranslatableStringHelper $translatableStringHelper + ) { $this->requestStack = $requestStack; $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; } - const MAX_LENGTH = 'maxLength'; - const MULTIPLE_CF_INLINE ='multipleCFInline'; - /** - * Create a form according to the maxLength option + * Create a form according to the maxLength option. * * if maxLength < 256 THEN the form type is 'text' * if not, THEN the form type is textarea - * - * @param FormBuilderInterface $builder - * @param CustomField $customField */ public function buildForm(FormBuilderInterface $builder, CustomField $customField) { - $options = $customField->getOptions(); + $options = $customField->getOptions(); - $type = ($options[self::MAX_LENGTH] < 256) ? TextType::class + $type = (256 > $options[self::MAX_LENGTH]) ? TextType::class : TextareaType::class; - $attrArray = array(); + $attrArray = []; - if(array_key_exists(self::MULTIPLE_CF_INLINE, $options) and - $options[self::MULTIPLE_CF_INLINE]) { + if ( + array_key_exists(self::MULTIPLE_CF_INLINE, $options) + and $options[self::MULTIPLE_CF_INLINE] + ) { $attrArray['class'] = 'multiple-cf-inline'; } - $builder->add($customField->getSlug(), $type, array( + $builder->add($customField->getSlug(), $type, [ 'label' => $this->translatableStringHelper->localize($customField->getName()), 'required' => false, - 'attr' => $attrArray - )); + 'attr' => $attrArray, + ]); } - public function render($value, CustomField $customField, $documentType = 'html') + public function buildOptionsForm(FormBuilderInterface $builder) { - $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.html.twig'; - if($documentType == 'csv') { - $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.csv.twig'; - } - - return $this->templating - ->render($template, array('text' => $value)); - } - - public function serialize($value, CustomField $customField) - { - return $value; + return $builder + ->add(self::MAX_LENGTH, IntegerType::class, ['empty_data' => 256]) + ->add(self::MULTIPLE_CF_INLINE, ChoiceType::class, [ + 'choices' => [ + 'Multiple boxes on the line' => '1', + 'One box on the line' => '0', + ], + 'label' => 'Box appearance', + 'expanded' => true, + ]); } public function deserialize($serialized, CustomField $customField) @@ -121,18 +100,20 @@ class CustomFieldText extends AbstractCustomField return 'Text field'; } - public function buildOptionsForm(FormBuilderInterface $builder) + public function render($value, CustomField $customField, $documentType = 'html') { - return $builder - ->add(self::MAX_LENGTH, IntegerType::class, array('empty_data' => 256)) - ->add(self::MULTIPLE_CF_INLINE, ChoiceType::class, array( - 'choices' => array( - 'Multiple boxes on the line' => '1', - 'One box on the line' => '0' - ), - 'label' => 'Box appearance', - 'expanded' => True - )) - ; + $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.html.twig'; + + if ('csv' == $documentType) { + $template = 'ChillCustomFieldsBundle:CustomFieldsRendering:text.csv.twig'; + } + + return $this->templating + ->render($template, ['text' => $value]); + } + + public function serialize($value, CustomField $customField) + { + return $value; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php index 64a7fbba8..1c59c7d2e 100644 --- a/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php +++ b/src/Bundle/ChillCustomFieldsBundle/CustomFields/CustomFieldTitle.php @@ -1,45 +1,33 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\CustomFields; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface; use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Form\Type\CustomFieldsTitleType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bundle\TwigBundle\TwigEngine; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bundle\TwigBundle\TwigEngine; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Chill\CustomFieldsBundle\Form\Type\CustomFieldsTitleType; class CustomFieldTitle extends AbstractCustomField { - const TYPE = 'type'; - const TYPE_TITLE = 'title'; - const TYPE_SUBTITLE = 'subtitle'; + public const TYPE = 'type'; + + public const TYPE_SUBTITLE = 'subtitle'; + + public const TYPE_TITLE = 'title'; private $requestStack; /** - * * @var TwigEngine */ private $templating; @@ -49,9 +37,11 @@ class CustomFieldTitle extends AbstractCustomField */ private $translatableStringHelper; - public function __construct(RequestStack $requestStack, TwigEngine $templating, - TranslatableStringHelper $translatableStringHelper) - { + public function __construct( + RequestStack $requestStack, + TwigEngine $templating, + TranslatableStringHelper $translatableStringHelper + ) { $this->requestStack = $requestStack; $this->templating = $templating; $this->translatableStringHelper = $translatableStringHelper; @@ -59,30 +49,29 @@ class CustomFieldTitle extends AbstractCustomField public function buildForm(FormBuilderInterface $builder, CustomField $customField) { - $builder->add($customField->getSlug(), CustomFieldsTitleType::class, array( + $builder->add($customField->getSlug(), CustomFieldsTitleType::class, [ 'label' => false, - 'attr' => array( + 'attr' => [ 'class' => 'cf-title', 'title' => $this->translatableStringHelper->localize($customField->getName()), - self::TYPE => $customField->getOptions()[self::TYPE ] - ) - )); + self::TYPE => $customField->getOptions()[self::TYPE], + ], + ]); } - public function render($value, CustomField $customField, $documentType = 'html') + public function buildOptionsForm(FormBuilderInterface $builder) { - return $this->templating - ->render('ChillCustomFieldsBundle:CustomFieldsRendering:title.html.twig', - array( - 'title' => $customField->getName(), - 'type' => $customField->getOptions()[self::TYPE] - ) - ); - } - - public function serialize($value, CustomField $customField) - { - return $value; + return $builder->add( + self::TYPE, + ChoiceType::class, + [ + 'choices' => [ + 'Main title' => self::TYPE_TITLE, + 'Subtitle' => self::TYPE_SUBTITLE, + ], + 'label' => 'Title level', + ] + ); } public function deserialize($serialized, CustomField $customField) @@ -100,16 +89,20 @@ class CustomFieldTitle extends AbstractCustomField return false; } - public function buildOptionsForm(FormBuilderInterface $builder) + public function render($value, CustomField $customField, $documentType = 'html') { - return $builder->add(self::TYPE, ChoiceType::class, - array( - 'choices' => array( - 'Main title' => self::TYPE_TITLE, - 'Subtitle' => self::TYPE_SUBTITLE - ), - 'label' => 'Title level', - ) - ); + return $this->templating + ->render( + 'ChillCustomFieldsBundle:CustomFieldsRendering:title.html.twig', + [ + 'title' => $customField->getName(), + 'type' => $customField->getOptions()[self::TYPE], + ] + ); + } + + public function serialize($value, CustomField $customField) + { + return $value; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/DataFixtures/ORM/LoadOption.php b/src/Bundle/ChillCustomFieldsBundle/DataFixtures/ORM/LoadOption.php index b859612c5..8d1ba01ba 100644 --- a/src/Bundle/ChillCustomFieldsBundle/DataFixtures/ORM/LoadOption.php +++ b/src/Bundle/ChillCustomFieldsBundle/DataFixtures/ORM/LoadOption.php @@ -1,56 +1,42 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\DataFixtures\ORM; +use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; -use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; use Doctrine\Persistence\ObjectManager; error_reporting(0); /** - * Load some Options - * - * - * @author Julien Fastré + * Load some Options. */ class LoadOption extends AbstractFixture implements OrderedFixtureInterface { /** - * - * @var \Faker\Generator - */ - public $fakerFr; - - /** - * * @var \Faker\Generator */ public $fakerEn; /** - * + * @var \Faker\Generator + */ + public $fakerFr; + + /** * @var \Faker\Generator */ public $fakerNl; + private $counter = 0; + public function __construct() { $this->fakerFr = \Faker\Factory::create('fr_FR'); @@ -72,110 +58,99 @@ class LoadOption extends AbstractFixture implements OrderedFixtureInterface $this->loadingWords($manager); $manager->flush(); - } - private function loadingWords(\Doctrine\Persistence\ObjectManager $manager) - { - echo "Loading some words...\n"; - - $parents = array( - array( - 'fr' => 'Categorie 1', - 'nl' => 'Categorie 1', - 'en' => 'Category 1' - ), - array( - 'fr' => 'Categorie 2', - 'nl' => 'Categorie 2', - 'en' => 'Category 2' - ) - ); - - foreach ($parents as $text) { - $parent = (new Option()) - ->setText($text) - ->setKey('word') - ; - $manager->persist($parent); - - //Load children - $expected_nb_children = rand(10, 50); - for ($i=0; $i < $expected_nb_children; $i++) { - $manager->persist($this->createChildOption($parent, array( - 'fr' => $this->fakerFr->word, - 'nl' => $this->fakerNl->word, - 'en' => $this->fakerEn->word - ))); - } - } - } - - private function loadingCompanies(\Doctrine\Persistence\ObjectManager $manager) - { - echo "Loading companies \n"; - $companiesParents = array( - array( - 'fr' => 'Grandes Entreprises', - 'nl' => 'Grotes Bedrijven', - 'en' => 'Big Companies' - ), - array( - 'fr' => 'Moyennes Entreprises', - 'nl' => 'Middelbare Bedrijven', - 'en' => 'Middle Companies' - ), - array( - 'fr' => 'Petites Entreprises', - 'nl' => 'Kleine Bedrijven', - 'en' => 'Little Companies' - ) - ); - - - foreach ($companiesParents as $text) { - - $parent = (new Option()) - ->setText($text) - ->setKey('company') - ; - $manager->persist($parent); - - //Load children - $expected_nb_children = rand(10, 50); - for ($i=0; $i < $expected_nb_children; $i++) { - - $companyName = $this->fakerFr->company; - - $manager->persist( - $this->createChildOption($parent, array( - 'fr' => $companyName, - 'nl' => $companyName, - 'en' => $companyName - ))); - } - - } - } - - private $counter = 0; - /** - * - * @param Option $parent - * @param array $text * @return Option */ private function createChildOption(Option $parent, array $text) { - $this->counter ++; + ++$this->counter; return (new Option()) - ->setText($text) - ->setParent($parent) - ->setActive(true) - ->setInternalKey($parent->getKey().'-'.$this->counter); - ; + ->setText($text) + ->setParent($parent) + ->setActive(true) + ->setInternalKey($parent->getKey() . '-' . $this->counter); } + private function loadingCompanies(ObjectManager $manager) + { + echo "Loading companies \n"; + $companiesParents = [ + [ + 'fr' => 'Grandes Entreprises', + 'nl' => 'Grotes Bedrijven', + 'en' => 'Big Companies', + ], + [ + 'fr' => 'Moyennes Entreprises', + 'nl' => 'Middelbare Bedrijven', + 'en' => 'Middle Companies', + ], + [ + 'fr' => 'Petites Entreprises', + 'nl' => 'Kleine Bedrijven', + 'en' => 'Little Companies', + ], + ]; + + foreach ($companiesParents as $text) { + $parent = (new Option()) + ->setText($text) + ->setKey('company'); + $manager->persist($parent); + + //Load children + $expected_nb_children = rand(10, 50); + + for ($i = 0; $i < $expected_nb_children; ++$i) { + $companyName = $this->fakerFr->company; + + $manager->persist( + $this->createChildOption($parent, [ + 'fr' => $companyName, + 'nl' => $companyName, + 'en' => $companyName, + ]) + ); + } + } + } + + private function loadingWords(ObjectManager $manager) + { + echo "Loading some words...\n"; + + $parents = [ + [ + 'fr' => 'Categorie 1', + 'nl' => 'Categorie 1', + 'en' => 'Category 1', + ], + [ + 'fr' => 'Categorie 2', + 'nl' => 'Categorie 2', + 'en' => 'Category 2', + ], + ]; + + foreach ($parents as $text) { + $parent = (new Option()) + ->setText($text) + ->setKey('word'); + $manager->persist($parent); + + //Load children + $expected_nb_children = rand(10, 50); + + for ($i = 0; $i < $expected_nb_children; ++$i) { + $manager->persist($this->createChildOption($parent, [ + 'fr' => $this->fakerFr->word, + 'nl' => $this->fakerNl->word, + 'en' => $this->fakerEn->word, + ])); + } + } + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php index f6aabc0f1..f94866921 100644 --- a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php +++ b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/ChillCustomFieldsExtension.php @@ -1,61 +1,69 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/fixtures.yaml'); $loader->load('services/controller.yaml'); $loader->load('services/command.yaml'); - + //add at least a blank array at 'customizable_entities' options - //$customizable_entities = (isset($config['customizables_entities']) - // && $config['customizables_entities'] !== FALSE) + //$customizable_entities = (isset($config['customizables_entities']) + // && $config['customizables_entities'] !== FALSE) // ? $config['customizables_entities'] : array(); - - $container->setParameter('chill_custom_fields.customizables_entities', - $config['customizables_entities']); - $container->setParameter('chill_custom_fields.show_empty_values', - $config['show_empty_values_in_views']); + + $container->setParameter( + 'chill_custom_fields.customizables_entities', + $config['customizables_entities'] + ); + $container->setParameter( + 'chill_custom_fields.show_empty_values', + $config['show_empty_values_in_views'] + ); } - - /* (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() - */ - public function prepend(ContainerBuilder $container) + + /* (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() + */ + public function prepend(ContainerBuilder $container) { // add form layout to twig resources $twigConfig['form_themes'][] = 'ChillCustomFieldsBundle:Form:fields.html.twig'; $container->prependExtensionConfig('twig', $twigConfig); - + //add routes for custom bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillCustomFieldsBundle/config/routes.yaml' - ) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillCustomFieldsBundle/config/routes.yaml', + ], + ], + ]); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/Configuration.php index 5bdd68cd4..dcbd219b1 100644 --- a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/Configuration.php @@ -1,70 +1,73 @@ getRootNode('chill_custom_fields'); - - $classInfo = "The class which may receive custom fields"; - $nameInfo = "The name which will appears in the user interface. May be translatable"; - $optionsInfo = "Options available for custom fields groups referencing this class"; - $optionsFormType = "The name of the form to append"; - $optionsFormOptionsInfos = "the arguments to pass the form"; - $customizableEntitiesInfo = "A list of customizable entities"; + + $classInfo = 'The class which may receive custom fields'; + $nameInfo = 'The name which will appears in the user interface. May be translatable'; + $optionsInfo = 'Options available for custom fields groups referencing this class'; + $optionsFormType = 'The name of the form to append'; + $optionsFormOptionsInfos = 'the arguments to pass the form'; + $customizableEntitiesInfo = 'A list of customizable entities'; $rootNode ->children() - ->arrayNode('customizables_entities') - ->info($customizableEntitiesInfo) - ->defaultValue(array()) - ->prototype('array') - ->children() - ->scalarNode('class')->isRequired()->info($classInfo) - ->end() - ->scalarNode('name') ->isRequired()->info($nameInfo) - ->end() - ->arrayNode('options') - ->info($optionsInfo) - ->defaultValue(array()) - ->useAttributeAsKey('key') - ->prototype('array') - ->children() - ->scalarNode('form_type') - ->isRequired() - ->info($optionsFormType) - ->end() - ->variableNode('form_options') - ->info($optionsFormOptionsInfos) - ->defaultValue(array()) - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() + ->arrayNode('customizables_entities') + ->info($customizableEntitiesInfo) + ->defaultValue([]) + ->prototype('array') + ->children() + ->scalarNode('class')->isRequired()->info($classInfo) + ->end() + ->scalarNode('name')->isRequired()->info($nameInfo) + ->end() + ->arrayNode('options') + ->info($optionsInfo) + ->defaultValue([]) + ->useAttributeAsKey('key') + ->prototype('array') + ->children() + ->scalarNode('form_type') + ->isRequired() + ->info($optionsFormType) + ->end() + ->variableNode('form_options') + ->info($optionsFormOptionsInfos) + ->defaultValue([]) + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() ->end() ->booleanNode('show_empty_values_in_views') - ->info('Show the empty value for custom fields in the views, timeline, ...') - ->defaultValue(true) + ->info('Show the empty value for custom fields in the views, timeline, ...') + ->defaultValue(true) ->end() - ->end() - ; + ->end(); return $treeBuilder; } diff --git a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/CustomFieldCompilerPass.php b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/CustomFieldCompilerPass.php index 8ea599a4f..ddd91b0ef 100644 --- a/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/CustomFieldCompilerPass.php +++ b/src/Bundle/ChillCustomFieldsBundle/DependencyInjection/CustomFieldCompilerPass.php @@ -1,43 +1,43 @@ - */ class CustomFieldCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasDefinition('chill.custom_field.provider')) { - throw new \LogicException('service chill.custom_field.provider ' + throw new LogicException('service chill.custom_field.provider ' . 'is not defined.'); } - + $definition = $container->getDefinition( 'chill.custom_field.provider' ); $taggedServices = $container->findTaggedServiceIds( 'chill.custom_field' - ); - + ); + foreach ($taggedServices as $id => $tagAttributes) { foreach ($tagAttributes as $attributes) { $definition->addMethodCall( 'addCustomField', - array(new Reference($id), $attributes["type"]) + [new Reference($id), $attributes['type']] ); } } } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php index d7fb1e769..95c5de37d 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomField.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Entity; @@ -24,23 +12,71 @@ namespace Chill\CustomFieldsBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * CustomField + * CustomField. * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="customfield") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class CustomField { + public const ONE_TO_MANY = 2; + + public const ONE_TO_ONE = 1; + /** - * @var integer + * @var bool + * + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * @var CustomFieldsGroup + * + * @ORM\ManyToOne( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup", + * inversedBy="customFields") + */ + private $customFieldGroup; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + + /** + * @var array + * + * @ORM\Column(type="json_array") + */ + private $name; + + /** + * @var array + * + * @ORM\Column(type="json_array") + */ + private $options = []; + + /** + * @var float + * + * @ORM\Column(type="float") + */ + private $ordering; + + /** + * @var bool + * + * @ORM\Column(type="boolean") + */ + private $required = false; + /** * @var string * @@ -56,94 +92,89 @@ class CustomField private $type; /** - * @var boolean + * Get customFieldGroup. * - * @ORM\Column(type="boolean") + * @return CustomFieldsGroup */ - private $active = true; - - /** - * @var array - * - * @ORM\Column(type="json_array") - */ - private $options = array(); - - /** - * @var array - * - * @ORM\Column(type="json_array") - */ - private $name; + public function getCustomFieldsGroup() + { + return $this->customFieldGroup; + } /** - * @var float + * Get id. * - * @ORM\Column(type="float") - */ - private $ordering; - - /** - * @var boolean - * - * @ORM\Column(type="boolean") - */ - private $required = FALSE; - - const ONE_TO_ONE = 1; - const ONE_TO_MANY = 2; - - /** - * @var CustomFieldsGroup - * - * @ORM\ManyToOne( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup", - * inversedBy="customFields") - */ - private $customFieldGroup; - - - /** - * Get id - * - * @return integer + * @return int */ public function getId() { return $this->id; } - + /** - * @return string + * Get name. + * + * @param mixed|null $locale + * + * @return array */ - function getSlug() + public function getName($locale = null) { - return $this->slug; + if ($locale) { + if (isset($this->name[$locale])) { + return $this->name[$locale]; + } + + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; + } + } + + return ''; + } + + return $this->name; } - + /** * @return array */ - function getOptions() + public function getOptions() { return $this->options; - } - - /** - * Set type - * - * @param string $type - * @return CustomField - */ - public function setType($type) - { - $this->type = $type; - - return $this; } /** - * Get type + * Get order. + * + * @return float + */ + public function getOrdering() + { + return $this->ordering; + } + + /** + * alias for isRequired. + * + * @return bool + */ + public function getRequired() + { + return $this->isRequired(); + } + + /** + * @return string + */ + public function getSlug() + { + return $this->slug; + } + + /** + * Get type. * * @return string */ @@ -152,11 +183,31 @@ class CustomField return $this->type; } - /** - * Set active + * Returns true if the custom field is active. + * + * @return bool + */ + public function isActive() + { + return $this->active; + } + + /** + * return true if the field required. + * + * @return bool + */ + public function isRequired() + { + return $this->required; + } + + /** + * Set active. + * + * @param bool $active * - * @param boolean $active * @return CustomField */ public function setActive($active) @@ -167,32 +218,13 @@ class CustomField } /** - * Returns true if the custom field is active - * - * @return boolean - */ - public function isActive() - { - return $this->active; - } - - /** - * Get customFieldGroup - * - * @return CustomFieldsGroup - */ - public function getCustomFieldsGroup() - { - return $this->customFieldGroup; - } - - /** - * Set customFieldGroup + * Set customFieldGroup. * * @param CustomFieldsGroup $customFieldGroup + * * @return CustomField */ - public function setCustomFieldsGroup(CustomFieldsGroup $customFieldGroup = null) + public function setCustomFieldsGroup(?CustomFieldsGroup $customFieldGroup = null) { $this->customFieldGroup = $customFieldGroup; @@ -200,9 +232,10 @@ class CustomField } /** - * Set name + * Set name. * * @param array $name + * * @return CustomField */ public function setName($name) @@ -213,34 +246,22 @@ class CustomField } /** - * Get name + * Set options. * - * @return array + * @return CustomField */ - public function getName($locale = null) + public function setOptions(array $options) { - if ($locale) { - if (isset($this->name[$locale])) { - return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } - } - } - - return ''; - - } else { - return $this->name; - }; + $this->options = $options; + + return $this; } /** - * Set order + * Set order. * * @param float $order + * * @return CustomField */ public function setOrdering($order) @@ -250,63 +271,36 @@ class CustomField return $this; } - /** - * Get order - * - * @return float - */ - public function getOrdering() + public function setRequired($required) { - return $this->ordering; - } - - /** - * Set options - * - * @param array $options - * @return CustomField - */ - public function setOptions(array $options) - { - $this->options = $options; + $this->required = $required; return $this; } - + /** * @param $slug + * * @return $this */ public function setSlug($slug) { $this->slug = $slug; + return $this; } - - /** - * alias for isRequired - * - * @return boolean - */ - public function getRequired() - { - return $this->isRequired(); - } - - /** - * return true if the field required - * - * @return boolean - */ - public function isRequired() - { - return $this->required; - } - public function setRequired($required) + /** + * Set type. + * + * @param string $type + * + * @return CustomField + */ + public function setType($type) { - $this->required = $required; + $this->type = $type; + return $this; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php index 06174a9a6..5fc6893d8 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldLongChoice/Option.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice; @@ -24,161 +14,63 @@ use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity( - * repositoryClass="Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository") + * repositoryClass="Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository") * @ORM\Table(name="custom_field_long_choice_options") - * - * @author Julien Fastré */ class Option { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * @var Collection + * @ORM\OneToMany( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", + * mappedBy="parent") + */ + private $children; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - - /** - * @var string - * @ORM\Column(type="string", length=15) - */ - private $key; - - /** - * A json representation of text (multilingual) - * - * @var array - * @ORM\Column(type="json_array") - */ - private $text; - - /** - * @var Collection - * @ORM\OneToMany( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", - * mappedBy="parent") - */ - private $children; - - /** - * @var Option - * @ORM\ManyToOne( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", - * inversedBy="children") - * @ORM\JoinColumn(nullable=true) - */ - private $parent; - + /** * @var string * @ORM\Column(type="string", length=50, name="internal_key") */ private $internalKey = ''; - + /** - * @var boolean - * @ORM\Column(type="boolean") + * @var string + * @ORM\Column(type="string", length=15) */ - private $active = true; - + private $key; + /** - * @return int + * @var Option + * @ORM\ManyToOne( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option", + * inversedBy="children") + * @ORM\JoinColumn(nullable=true) */ - public function getId() - { - return $this->id; - } - + private $parent; + /** - * @return string + * A json representation of text (multilingual). + * + * @var array + * @ORM\Column(type="json_array") */ - public function getKey() - { - return $this->key; - } - - /** - * @return array - */ - public function getText() - { - return $this->text; - } - - /** - * @return Collection - */ - public function getChildren() - { - return $this->children; - } - - /** - * @return Option - */ - public function getParent() - { - return $this->parent; - } - - /** - * @param $key - * @return $this - */ - public function setKey($key) - { - $this->key = $key; - return $this; - } - - /** - * @param array $text - * @return $this - */ - public function setText(array $text) - { - $this->text = $text; - return $this; - } - - /** - * @param Option|null $parent - * @return $this - */ - public function setParent(Option $parent = null) - { - $this->parent = $parent; - $this->key = $parent->getKey(); - return $this; - } - - /** - * - * @return boolean - */ - public function hasParent() - { - return $this->parent === NULL ? false : true; - } - - /** - * @return string - */ - public function getInternalKey() - { - return $this->internalKey; - } - - /** - * @return bool - */ - public function isActive() - { - return $this->active; - } - + private $text; + /** * @return bool */ @@ -186,25 +78,125 @@ class Option { return $this->isActive(); } - + /** - * @param $internal_key - * @return $this + * @return Collection */ - public function setInternalKey($internal_key) + public function getChildren() { - $this->internalKey = $internal_key; - return $this; + return $this->children; } - + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getInternalKey() + { + return $this->internalKey; + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * @return Option + */ + public function getParent() + { + return $this->parent; + } + + /** + * @return array + */ + public function getText() + { + return $this->text; + } + + /** + * @return bool + */ + public function hasParent() + { + return null === $this->parent ? false : true; + } + + /** + * @return bool + */ + public function isActive() + { + return $this->active; + } + /** * @param $active + * * @return $this */ public function setActive($active) { $this->active = $active; + + return $this; + } + + /** + * @param $internal_key + * + * @return $this + */ + public function setInternalKey($internal_key) + { + $this->internalKey = $internal_key; + + return $this; + } + + /** + * @param $key + * + * @return $this + */ + public function setKey($key) + { + $this->key = $key; + + return $this; + } + + /** + * @return $this + */ + public function setParent(?Option $parent = null) + { + $this->parent = $parent; + $this->key = $parent->getKey(); + + return $this; + } + + /** + * @return $this + */ + public function setText(array $text) + { + $this->text = $text; + return $this; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsDefaultGroup.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsDefaultGroup.php index 28d0afb78..e219fa3e8 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsDefaultGroup.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsDefaultGroup.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Entity; @@ -24,26 +12,27 @@ namespace Chill\CustomFieldsBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * CustomFieldsDefaultGroup + * CustomFieldsDefaultGroup. * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table( * name="customfieldsdefaultgroup", * uniqueConstraints={@ORM\UniqueConstraint( - * name="unique_entity", - * columns={"entity"} - * )}) + * name="unique_entity", + * columns={"entity"} + * )}) */ class CustomFieldsDefaultGroup { /** - * @var integer + * @var CustomFieldsGroup * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") + * @ORM\ManyToOne( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup") + * + * sf4 check: option inversedBy="customFields" return inconsistent error mapping !! */ - private $id; + private $customFieldsGroup; /** * @var string @@ -53,40 +42,26 @@ class CustomFieldsDefaultGroup private $entity; /** - * @var CustomFieldsGroup + * @var int * - * @ORM\ManyToOne( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup") - * - * sf4 check: option inversedBy="customFields" return inconsistent error mapping !! + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") */ - private $customFieldsGroup; + private $id; /** - * Get id + * Get customFieldsGroup. * - * @return integer + * @return CustomFieldsGroup */ - public function getId() + public function getCustomFieldsGroup() { - return $this->id; + return $this->customFieldsGroup; } /** - * Set entity - * - * @param string $entity - * @return CustomFieldsDefaultGroup - */ - public function setEntity($entity) - { - $this->entity = $entity; - - return $this; - } - - /** - * Get entity + * Get entity. * * @return string */ @@ -96,9 +71,20 @@ class CustomFieldsDefaultGroup } /** - * Set customFieldsGroup + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Set customFieldsGroup. * * @param CustomFieldsGroup $customFieldsGroup * + * * @return CustomFieldsDefaultGroup */ public function setCustomFieldsGroup($customFieldsGroup) @@ -109,12 +95,16 @@ class CustomFieldsDefaultGroup } /** - * Get customFieldsGroup + * Set entity. * - * @return CustomFieldsGroup + * @param string $entity + * + * @return CustomFieldsDefaultGroup */ - public function getCustomFieldsGroup() + public function setEntity($entity) { - return $this->customFieldsGroup; + $this->entity = $entity; + + return $this; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php index f9bb90d6d..091bb3ea6 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php +++ b/src/Bundle/ChillCustomFieldsBundle/Entity/CustomFieldsGroup.php @@ -1,40 +1,56 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * CustomFieldGroup + * CustomFieldGroup. * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="customfieldsgroup") */ class CustomFieldsGroup { /** - * @var integer + * The custom fields of the group that are active. + * This variable if null, if this informations has not been computed. + * + * @var array|null + */ + private $activeCustomFields; + + /** + * The custom fields of the group. + * The custom fields are asc-ordered regarding to their property "ordering". + * + * @var Collection + * + * @ORM\OneToMany( + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomField", + * mappedBy="customFieldGroup") + * @ORM\OrderBy({"ordering": "ASC"}) + */ + private $customFields; + + /** + * @var string + * + * @ORM\Column(type="string", length=255) + */ + private $entity; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -49,42 +65,13 @@ class CustomFieldsGroup */ private $name; - /** - * @var string - * - * @ORM\Column(type="string", length=255) - */ - private $entity; - - /** - * The custom fields of the group. - * The custom fields are asc-ordered regarding to their property "ordering". - * - * @var Collection $customFields - * - * @ORM\OneToMany( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomField", - * mappedBy="customFieldGroup") - * @ORM\OrderBy({"ordering" = "ASC"}) - */ - private $customFields; - - /** - * The custom fields of the group that are active. - * This variable if null, if this informations has not been computed. - * - * @var array|null - */ - private $activeCustomFields = null; - /** * @var array * * @ORM\Column(type="json_array") */ - private $options = array(); - - + private $options = []; + /** * CustomFieldsGroup constructor. */ @@ -94,9 +81,8 @@ class CustomFieldsGroup } /** - * Add customField + * Add customField. * - * @param CustomField $customField * @return CustomFieldsGroup */ public function addCustomField(CustomField $customField) @@ -107,34 +93,17 @@ class CustomFieldsGroup } /** - * Remove customField - * - * @param CustomField $customField - */ - public function removeCustomField(CustomField $customField) - { - $this->customFields->removeElement($customField); - } - - /** - * @return Collection - */ - public function getCustomFields() - { - return $this->customFields; - } - - /** - * Get all the custom + * Get all the custom. * * @return Collection */ public function getActiveCustomFields() { - if($this->activeCustomFields === null) { - $this->activeCustomFields = array(); + if (null === $this->activeCustomFields) { + $this->activeCustomFields = []; + foreach ($this->customFields as $cf) { - if($cf->isActive()) { + if ($cf->isActive()) { array_push($this->activeCustomFields, $cf); } } @@ -142,11 +111,29 @@ class CustomFieldsGroup return $this->activeCustomFields; } - + /** - * Get id + * @return Collection + */ + public function getCustomFields() + { + return $this->customFields; + } + + /** + * Get entity. * - * @return integer + * @return string + */ + public function getEntity() + { + return $this->entity; + } + + /** + * Get id. + * + * @return int */ public function getId() { @@ -154,48 +141,55 @@ class CustomFieldsGroup } /** - * Set name + * Get name. * - * @param array $name - * @return CustomFieldsGroup - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name + * @param mixed|null $language * * @return array */ public function getName($language = null) { - //TODO set this in a service, PLUS twig function - if ($language) { - if (isset($this->name[$language])) { - return $this->name[$language]; - } else { - foreach ($this->name as $name) { + //TODO set this in a service, PLUS twig function + if ($language) { + if (isset($this->name[$language])) { + return $this->name[$language]; + } + + foreach ($this->name as $name) { if (!empty($name)) { - return $name; + return $name; } - } - } - - return ''; - - } else { - return $this->name; - } + } + + return ''; + } + + return $this->name; } /** - * Set entity + * get options array. + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * Remove customField. + */ + public function removeCustomField(CustomField $customField) + { + $this->customFields->removeElement($customField); + } + + /** + * Set entity. * * @param string $entity + * * @return CustomFieldsGroup */ public function setEntity($entity) @@ -206,34 +200,28 @@ class CustomFieldsGroup } /** - * Get entity + * Set name. * - * @return string + * @param array $name + * + * @return CustomFieldsGroup */ - public function getEntity() + public function setName($name) { - return $this->entity; - } - - /** - * get options array - * - * @return array - */ - public function getOptions() - { - return $this->options; + $this->name = $name; + + return $this; } /** - * set options array - * - * @param array $options + * set options array. + * * @return CustomFieldsGroup */ public function setOptions(array $options) { $this->options = $options; + return $this; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/EntityRepository/CustomFieldLongChoice/OptionRepository.php b/src/Bundle/ChillCustomFieldsBundle/EntityRepository/CustomFieldLongChoice/OptionRepository.php index 58f8ee302..134417df6 100644 --- a/src/Bundle/ChillCustomFieldsBundle/EntityRepository/CustomFieldLongChoice/OptionRepository.php +++ b/src/Bundle/ChillCustomFieldsBundle/EntityRepository/CustomFieldLongChoice/OptionRepository.php @@ -1,77 +1,62 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice; -use Doctrine\ORM\EntityRepository; use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; +use Doctrine\ORM\EntityRepository; -/** - * - * - * @author Julien Fastré - */ class OptionRepository extends EntityRepository { /** - * * @param string $key + * @param mixed $includeParents + * @param mixed $active + * * @return Option[] */ public function findFilteredByKey($key, $includeParents = true, $active = true) { $qb = $this->createQueryBuilder('option'); $qb->where('option.key = :key'); - - if ($active === true){ + + if (true === $active) { $qb->andWhere('option.active = true'); } - - if ($includeParents === false) { + + if (false === $includeParents) { $qb->andWhere('option.parent IS NOT NULL'); - - if ($active === TRUE) { + + if (true === $active) { $qb->join('option.parent', 'p'); $qb->andWhere('p.active = true'); } } - + $qb->setParameter('key', $key); - + return $qb->getQuery()->getResult(); } - + /** - * * @return string[] */ public function getKeys() { $keys = $this->createQueryBuilder('option') - ->select('option.key') - ->distinct() - ->getQuery() - ->getScalarResult(); - - return array_map(function($r) { + ->select('option.key') + ->distinct() + ->getQuery() + ->getScalarResult(); + + return array_map(function ($r) { return $r['key']; }, $keys); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldType.php b/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldType.php index cd3c7497d..6e35b33fe 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldType.php @@ -1,43 +1,47 @@ om = $om; $this->translatableStringHelper = $translatableStringHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ + public function buildForm(FormBuilderInterface $builder, array $options) { - - $customFieldsList = array(); + $customFieldsList = []; foreach ($this->customFieldProvider->getAllFields() as $key => $field) { $customFieldsList[$key] = $field->getName(); @@ -63,33 +63,32 @@ class CustomFieldType extends AbstractType $builder ->add('name', TranslatableStringFormType::class) - ->add('active', CheckboxType::class, array('required' => false)); + ->add('active', CheckboxType::class, ['required' => false]); - if ($options['group_widget'] === 'entity') { - $builder->add('customFieldsGroup', EntityType::class, array( - 'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup', - 'choice_label' => function($g) { + if ('entity' === $options['group_widget']) { + $builder->add('customFieldsGroup', EntityType::class, [ + 'class' => 'ChillCustomFieldsBundle:CustomFieldsGroup', + 'choice_label' => function ($g) { return $this->translatableStringHelper->localize($g->getName()); - } - )); - } elseif ($options['group_widget'] === 'hidden') { + }, + ]); + } elseif ('hidden' === $options['group_widget']) { $builder->add('customFieldsGroup', HiddenType::class); $builder->get('customFieldsGroup') - ->addViewTransformer(new CustomFieldsGroupToIdTransformer($this->om)); + ->addViewTransformer(new CustomFieldsGroupToIdTransformer($this->om)); } else { - throw new \LogicException('The value of group_widget is not handled'); + throw new LogicException('The value of group_widget is not handled'); } $builder ->add('ordering', NumberType::class) - ->add('required', CheckboxType::class, array( + ->add('required', CheckboxType::class, [ 'required' => false, //'expanded' => TRUE, - 'label' => 'Required field' - )) - ->add('type', HiddenType::class, array('data' => $options['type'])) - ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) - { + 'label' => 'Required field', + ]) + ->add('type', HiddenType::class, ['data' => $options['type']]) + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $customField = $event->getData(); $form = $event->getForm(); @@ -101,16 +100,15 @@ class CustomFieldType extends AbstractType } }); - $builder->add( $this->customFieldProvider ->getCustomFieldByType($options['type']) ->buildOptionsForm( $builder - ->create('options', null, array('compound' => true)) - ->setRequired(false) - ) - ); + ->create('options', null, ['compound' => true]) + ->setRequired(false) + ) + ); } /** @@ -118,14 +116,14 @@ class CustomFieldType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomField', + ]); - $resolver->setRequired(array('type', 'group_widget')) - ->addAllowedValues('type', array_keys($this->customFieldProvider->getAllFields())) - ->addAllowedValues('group_widget', array('hidden', 'entity')) - ->setDefault('group_widget', 'entity'); + $resolver->setRequired(['type', 'group_widget']) + ->addAllowedValues('type', array_keys($this->customFieldProvider->getAllFields())) + ->addAllowedValues('group_widget', ['hidden', 'entity']) + ->setDefault('group_widget', 'entity'); } /** diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php b/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php index 64e461c95..bec9d4188 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/CustomFieldsGroupType.php @@ -1,21 +1,25 @@ translator = $translator; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ //TODO : details about the function public function buildForm(FormBuilderInterface $builder, array $options) { //prepare translation - $entities = array(); - $customizableEntities = array(); //TODO : change name too close than $this->customizableEntities + $entities = []; + $customizableEntities = []; //TODO : change name too close than $this->customizableEntities - foreach($this->customizableEntities as $key => $definition) { + foreach ($this->customizableEntities as $key => $definition) { $entities[$definition['class']] = $this->translator->trans($definition['name']); $customizableEntities[$definition['class']] = $definition; } $builder ->add('name', TranslatableStringFormType::class) - ->add('entity', ChoiceType::class, array( - 'choices' => array_combine(array_values($entities),array_keys($entities)), - )) - ; + ->add('entity', ChoiceType::class, [ + 'choices' => array_combine(array_values($entities), array_keys($entities)), + ]); - $builder->addEventListener(FormEvents::POST_SET_DATA, - function(FormEvent $event) use ($customizableEntities, $builder){ - $form = $event->getForm(); - $group = $event->getData(); + $builder->addEventListener( + FormEvents::POST_SET_DATA, + function (FormEvent $event) use ($customizableEntities, $builder) { + $form = $event->getForm(); + $group = $event->getData(); - //stop the function if entity is not set - if ($group->getEntity() === NULL) { - return; - } + //stop the function if entity is not set + if ($group->getEntity() === null) { + return; + } - if (count($customizableEntities[$group->getEntity()]['options']) > 0) { - $optionBuilder = $builder - ->getFormFactory() - ->createBuilderForProperty( - 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup', - 'options' - ) - ->create('options', null, array( - 'compound' => true, - 'auto_initialize' => false, - 'required' => false) - ); - } + if (count($customizableEntities[$group->getEntity()]['options']) > 0) { + $optionBuilder = $builder + ->getFormFactory() + ->createBuilderForProperty( + 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup', + 'options' + ) + ->create( + 'options', + null, + [ + 'compound' => true, + 'auto_initialize' => false, + 'required' => false, ] + ); + } - foreach($customizableEntities[$group->getEntity()]['options'] as $key => $option) { - $optionBuilder - ->add($key, $option['form_type'], $option['form_options']) - ; - } - if (isset($optionBuilder) && $optionBuilder->count() > 0) { - $form->add($optionBuilder->getForm()); - } + foreach ($customizableEntities[$group->getEntity()]['options'] as $key => $option) { + $optionBuilder + ->add($key, $option['form_type'], $option['form_options']); + } - }); + if (isset($optionBuilder) && $optionBuilder->count() > 0) { + $form->add($optionBuilder->getForm()); + } + } + ); } /** @@ -93,9 +96,9 @@ class CustomFieldsGroupType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup', + ]); } /** diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldDataTransformer.php b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldDataTransformer.php index f54c8b818..3efc2fa82 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldDataTransformer.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldDataTransformer.php @@ -1,43 +1,48 @@ - */ class CustomFieldDataTransformer implements DataTransformerInterface { - private $customFieldDefinition; - /** - * * @var \Chill\CustomFieldsBundle\Entity\CustomField */ private $customField; - - public function __construct(CustomFieldInterface $customFieldDefinition, - CustomField $customField) - { + + private $customFieldDefinition; + + public function __construct( + CustomFieldInterface $customFieldDefinition, + CustomField $customField + ) { $this->customFieldDefinition = $customFieldDefinition; $this->customField = $customField; } - + public function reverseTransform($value) { - return $this->customFieldDefinition->serialize($value, - $this->customField); + return $this->customFieldDefinition->serialize( + $value, + $this->customField + ); } public function transform($value) { - return $this->customFieldDefinition->deserialize($value, - $this->customField); + return $this->customFieldDefinition->deserialize( + $value, + $this->customField + ); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php index f637281ba..d0054dead 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/CustomFieldsGroupToIdTransformer.php @@ -1,11 +1,18 @@ om = $om; } - /** - * Transforms an custom_field_group to a string (id) - * - * @param CustomFieldsGroup|null $customFieldsGroup - * @return string - */ - public function transform($customFieldsGroup) - { - if (null === $customFieldsGroup) { - return ""; - } - - if (!$customFieldsGroup instanceof CustomFieldsGroup) { - throw new TransformationFailedException(sprintf('Transformation failed: ' - . 'the expected type of the transforme function is an ' - . 'object of type Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' - . '%s given (value : %s)', gettype($customFieldsGroup), - $customFieldsGroup)); - } - - return $customFieldsGroup->getId(); - } - /** * Transforms a string (id) to an object (CustomFieldsGroup). * * @param string $id - * @return CustomFieldsGroup|null + * * @throws TransformationFailedException if object (report) is not found. + * + * @return CustomFieldsGroup|null */ public function reverseTransform($id) { if (!$id) { return null; } - + if ($id instanceof CustomFieldsGroup) { throw new TransformationFailedException(sprintf( - 'The transformation failed: the expected argument on ' + 'The transformation failed: the expected argument on ' . 'reverseTransform is an object of type int,' . 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' - . 'given', gettype($id))); + . 'given', + gettype($id) + )); } $customFieldsGroup = $this->om - ->getRepository('ChillCustomFieldsBundle:customFieldsGroup')->find($id) - ; + ->getRepository('ChillCustomFieldsBundle:customFieldsGroup')->find($id); if (null === $customFieldsGroup) { throw new TransformationFailedException(sprintf( @@ -79,4 +63,31 @@ class CustomFieldsGroupToIdTransformer implements DataTransformerInterface return $customFieldsGroup; } -} \ No newline at end of file + + /** + * Transforms an custom_field_group to a string (id). + * + * @param CustomFieldsGroup|null $customFieldsGroup + * + * @return string + */ + public function transform($customFieldsGroup) + { + if (null === $customFieldsGroup) { + return ''; + } + + if (!$customFieldsGroup instanceof CustomFieldsGroup) { + throw new TransformationFailedException(sprintf( + 'Transformation failed: ' + . 'the expected type of the transforme function is an ' + . 'object of type Chill\CustomFieldsBundle\Entity\CustomFieldsGroup, ' + . '%s given (value : %s)', + gettype($customFieldsGroup), + $customFieldsGroup + )); + } + + return $customFieldsGroup->getId(); + } +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php index 6b54df801..c98acd43b 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/DataTransformer/JsonCustomFieldToArrayTransformer.php @@ -1,20 +1,24 @@ om = $om; @@ -22,97 +26,52 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { $customFields = $this->om ->getRepository('ChillCustomFieldsBundle:CustomField') ->findAll(); - + $customFieldsLablels = array_map( - function($e) { return $e->getLabel(); }, - $customFields); + function ($e) { + return $e->getLabel(); + }, + $customFields + ); $customFieldsByLabel = array_combine($customFieldsLablels, $customFields); $this->customField = $customFieldsByLabel; } - public function transform($customFieldsJSON) - { - echo $customFieldsJSON; - - if($customFieldsJSON === null) { // lors de la creation - $customFieldsArray = array(); - } else { - $customFieldsArray = json_decode($customFieldsJSON,true); - } - - /* - echo "
- 4 -
"; - - var_dump($customFieldsArray); - - echo "
- 5 -
"; - */ - - $customFieldsArrayRet = array(); - - foreach ($customFieldsArray as $key => $value) { - $traited = false; - if(array_key_exists($key, $this->customField)) { - $type = $this->customField[$key]->getType(); - if(strpos($type,'ManyToOne') === 0) { - if(strpos($type,'ManyToOnePersist') ===0) { - $entityClass = substr($type, 17, -1); - } else { - $entityClass = substr($type, 10, -1); - } - - $customFieldsArrayRet[$key] = $this->om - ->getRepository('ChillCustomFieldsBundle:' . $entityClass) - ->findOneById($value); - $traited = true; - } else if ($type === 'ManyToMany(Adress)') { - $customFieldsArrayRet[$key] = $value; - } - } - - if(! $traited) { - $customFieldsArrayRet[$key] = $value; - } - } - - var_dump($customFieldsArrayRet); - - return $customFieldsArrayRet; - } - public function reverseTransform($customFieldsArray) { /* echo "
- - 7 -
"; - + var_dump(array_keys($customFieldsArray)); - + echo "
- - 8 -
"; var_dump(array_keys($this->customField)); echo "
- - 9 -
"; - */ + */ //var_dump($customFieldsArray); - $customFieldsArrayRet = array(); + $customFieldsArrayRet = []; foreach ($customFieldsArray as $key => $value) { $traited = false; - if(array_key_exists($key, $this->customField)) { + + if (array_key_exists($key, $this->customField)) { $type = $this->customField[$key]->getType(); - if(strpos($type,'ManyToOne') === 0) { + + if (strpos($type, 'ManyToOne') === 0) { // pour le manytoone() faire // un update du form en js ? : http://symfony.com/fr/doc/current/cookbook/form/form_collections.html // //$entityClass = substr($type, 10, -1); //echo $entityClasss; - if(strpos($type, 'ManyToOnePersist') === 0) { - // PEUT ETRE A FAIRE SI SEULEMENT $value->getId() ne renvoie rien... + if (strpos($type, 'ManyToOnePersist') === 0) { + // PEUT ETRE A FAIRE SI SEULEMENT $value->getId() ne renvoie rien... // // $this->om->persist($value); // pas bon ici @@ -121,7 +80,7 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { // et faire le persist qd fait sur l'obj parent // regarder : http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html // ou : http://symfony.com/doc/current/cookbook/doctrine/event_listeners_subscribers.html - // dans yml : + // dans yml : // lifecycleCallbacks: // prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersist ] $this->om->flush(); // sinon l'id pose pbm @@ -132,14 +91,65 @@ class JsonCustomFieldToArrayTransformer implements DataTransformerInterface { } } - if(! $traited) { + if (!$traited) { $customFieldsArrayRet[$key] = $value; } - } //echo json_encode($customFieldsArrayRet); return json_encode($customFieldsArrayRet); } -} \ No newline at end of file + + public function transform($customFieldsJSON) + { + echo $customFieldsJSON; + + if (null === $customFieldsJSON) { // lors de la creation + $customFieldsArray = []; + } else { + $customFieldsArray = json_decode($customFieldsJSON, true); + } + + /* + echo "
- 4 -
"; + + var_dump($customFieldsArray); + + echo "
- 5 -
"; + */ + + $customFieldsArrayRet = []; + + foreach ($customFieldsArray as $key => $value) { + $traited = false; + + if (array_key_exists($key, $this->customField)) { + $type = $this->customField[$key]->getType(); + + if (strpos($type, 'ManyToOne') === 0) { + if (strpos($type, 'ManyToOnePersist') === 0) { + $entityClass = substr($type, 17, -1); + } else { + $entityClass = substr($type, 10, -1); + } + + $customFieldsArrayRet[$key] = $this->om + ->getRepository('ChillCustomFieldsBundle:' . $entityClass) + ->findOneById($value); + $traited = true; + } elseif ('ManyToMany(Adress)' === $type) { + $customFieldsArrayRet[$key] = $value; + } + } + + if (!$traited) { + $customFieldsArrayRet[$key] = $value; + } + } + + var_dump($customFieldsArrayRet); + + return $customFieldsArrayRet; + } +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextExtension.php b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextExtension.php index 24cf4e4f4..ce6c9b65f 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextExtension.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextExtension.php @@ -1,47 +1,29 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Form\Extension; use Symfony\Component\Form\AbstractTypeExtension; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; -use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * This extension create the possibility to add some text - * after the input. - * - * This can be used to print the units of the field, or some text. - * - * This class must be extended by Extension class specifics to each input. + * after the input. * - * @author Julien Fastré + * This can be used to print the units of the field, or some text. + * + * This class must be extended by Extension class specifics to each input. */ abstract class PostTextExtension extends AbstractTypeExtension { - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefined(array('post_text')); - } - public function buildView(FormView $view, FormInterface $form, array $options) { if (array_key_exists('post_text', $options)) { @@ -50,4 +32,8 @@ abstract class PostTextExtension extends AbstractTypeExtension } } + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefined(['post_text']); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextIntegerExtension.php b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextIntegerExtension.php index 5b42411a5..107fefd05 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextIntegerExtension.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextIntegerExtension.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Form\Extension; @@ -22,15 +12,12 @@ namespace Chill\CustomFieldsBundle\Form\Extension; use Symfony\Component\Form\Extension\Core\Type\IntegerType; /** - * This class add the PostTextExtension to integer fields - * - * @author Julien Fastré + * This class add the PostTextExtension to integer fields. */ class PostTextIntegerExtension extends PostTextExtension { public function getExtendedType() { - return IntegerType::class; + return IntegerType::class; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextNumberExtension.php b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextNumberExtension.php index 7501fbc67..356c293ac 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextNumberExtension.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Extension/PostTextNumberExtension.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Form\Extension; @@ -22,9 +12,7 @@ namespace Chill\CustomFieldsBundle\Form\Extension; use Symfony\Component\Form\Extension\Core\Type\NumberType; /** - * This class add the PostTextExtension to number fields - * - * @author Julien Fastré + * This class add the PostTextExtension to number fields. */ class PostTextNumberExtension extends PostTextExtension { @@ -32,5 +20,4 @@ class PostTextNumberExtension extends PostTextExtension { return NumberType::class; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoiceWithOtherType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoiceWithOtherType.php index 15a2e4a22..debc3cdf5 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoiceWithOtherType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoiceWithOtherType.php @@ -1,17 +1,22 @@ - * + * Return a choice widget with an "other" option. */ class ChoiceWithOtherType extends AbstractType { @@ -22,7 +27,6 @@ class ChoiceWithOtherType extends AbstractType */ public function buildForm(FormBuilderInterface $builder, array $options) { - //add an 'other' entry in choices array $options['choices'][$this->otherValueLabel] = '_other'; //ChoiceWithOther must always be expanded @@ -31,9 +35,8 @@ class ChoiceWithOtherType extends AbstractType $options['empty_data'] = null; $builder - ->add('_other', TextType::class, array('required' => false)) - ->add('_choices', ChoiceType::class, $options) - ; + ->add('_other', TextType::class, ['required' => false]) + ->add('_choices', ChoiceType::class, $options); } /* (non-PHPdoc) @@ -42,12 +45,11 @@ class ChoiceWithOtherType extends AbstractType public function configureOptions(OptionsResolver $resolver) { $resolver - ->setRequired(array('choices')) - ->setAllowedTypes('choices', array('array')) - ->setDefaults(array( - 'multiple' => false - )) - ; + ->setRequired(['choices']) + ->setAllowedTypes('choices', ['array']) + ->setDefaults([ + 'multiple' => false, + ]); } public function getBlockPrefix() diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php index 7d8457783..eb7fb6363 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesListType.php @@ -1,35 +1,41 @@ add('name', TranslatableStringFormType::class) - ->add('active', CheckboxType::class, array( - 'required' => false - )) + ->add('active', CheckboxType::class, [ + 'required' => false, + ]) ->add('slug', HiddenType::class) - ->addEventListener(FormEvents::SUBMIT, function(FormEvent $event) { + ->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); $formData = $form->getData(); - if (NULL === $formData['slug']) { + if (null === $formData['slug']) { $slug = uniqid(rand(), true); $data['slug'] = $slug; @@ -38,11 +44,9 @@ class ChoicesListType extends AbstractType $data['slug'] = $formData['slug']; $event->setData($data); } - }) - ; + }); } - /* * * @see \Symfony\Component\Form\FormTypeInterface::getName() @@ -51,5 +55,4 @@ class ChoicesListType extends AbstractType { return 'cf_choices_list'; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesType.php index 709f3498f..c6685caa7 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/ChoicesType.php @@ -1,15 +1,17 @@ - * - */ class ChoicesType extends AbstractType { public function getBlockPrefix() diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldType.php index 68a1e15e8..c3ea7bc52 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldType.php @@ -1,44 +1,32 @@ - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Form\Type; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; -use Chill\CustomFieldsBundle\Form\DataTransformer\JsonCustomFieldToArrayTransformer; -use Doctrine\Persistence\ObjectManager; -use Chill\CustomFieldsBundle\Form\AdressType; -use Chill\CustomFieldsBundle\Service\CustomFieldProvider; -use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldTitle; class CustomFieldType extends AbstractType { + /** + * @var CustomFieldCompiler + */ + private $customFieldCompiler; /** * @var ObjectManager */ private $om; - /** - * - * @var CustomFieldCompiler - */ - private $customFieldCompiler; - - /** - * @param ObjectManager $om - */ public function __construct(ObjectManager $om, CustomFieldProvider $compiler) { $this->om = $om; @@ -55,17 +43,15 @@ class CustomFieldType extends AbstractType } } - public function configureOptions(\Symfony\Component\OptionsResolver\OptionsResolver $resolver) + public function configureOptions(OptionsResolver $resolver) { $resolver - ->setRequired(array('group')) - ->addAllowedTypes('group', array('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup')) - ; + ->setRequired(['group']) + ->addAllowedTypes('group', ['Chill\CustomFieldsBundle\Entity\CustomFieldsGroup']); } public function getBlockPrefix() { return 'custom_field'; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldsTitleType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldsTitleType.php index 276d9eaff..7d65b115c 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldsTitleType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/CustomFieldsTitleType.php @@ -1,23 +1,12 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\CustomFieldsBundle\Form\Type; use Symfony\Component\Form\AbstractType; @@ -27,12 +16,10 @@ class CustomFieldsTitleType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { - } public function getBlockPrefix() { return 'custom_field_title'; } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Form/Type/LinkedCustomFieldsType.php b/src/Bundle/ChillCustomFieldsBundle/Form/Type/LinkedCustomFieldsType.php index a5e955fdd..c705c3224 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Form/Type/LinkedCustomFieldsType.php +++ b/src/Bundle/ChillCustomFieldsBundle/Form/Type/LinkedCustomFieldsType.php @@ -1,31 +1,21 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Form\Type; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Form\FormInterface; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; /** * This type create a Choice field with custom fields as choices. @@ -33,19 +23,11 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType; * This type can only be associated with a customFieldsGroup type. The field * is populated when the data (a customFieldsGroup entity) is associated with * the form - * - * @author Julien Fastré */ class LinkedCustomFieldsType extends AbstractType { /** - * - * @var TranslatableStringHelper - */ - private $translatableStringHelper; - - /** - * The name for the choice field + * The name for the choice field. * * Extracted from builder::getName * @@ -57,24 +39,71 @@ class LinkedCustomFieldsType extends AbstractType * the option of the form. * * @internal options are stored at the class level to be reused by appendChoice, after data are setted + * * @var array */ - private $options = array(); + private $options = []; + + /** + * @var TranslatableStringHelper + */ + private $translatableStringHelper; public function __construct(TranslatableStringHelper $helper) { $this->translatableStringHelper = $helper; } + /** + * append Choice on POST_SET_DATA event. + * + * Choices are extracted from custom_field_group (the data associated + * with the root form) + * + * @return void + */ + public function appendChoice(FormEvent $event) + { + $rootForm = $this->getRootForm($event->getForm()); + $group = $rootForm->getData(); + + if (null === $group) { + return; + } + + $choices = []; + + foreach ($group->getCustomFields() as $customFields) { + $choices[$customFields->getSlug()] = + $this->translatableStringHelper + ->localize($customFields->getName()); + } + + $options = array_merge($this->options, [ + 'choices' => $choices, + ]); + + $event->getForm()->getParent()->add( + $this->choiceName, + ChoiceType::class, + $options + ); + } public function buildForm(FormBuilderInterface $builder, array $options) { $this->choiceName = $builder->getName(); $this->options = $options; - $builder->addEventListener(FormEvents::POST_SET_DATA, - array($this, 'appendChoice')) - ; + $builder->addEventListener( + FormEvents::POST_SET_DATA, + [$this, 'appendChoice'] + ); + } + + public function getBlockPrefix() + { + return 'custom_fields_group_linked_custom_fields'; } public function getParent() @@ -83,56 +112,16 @@ class LinkedCustomFieldsType extends AbstractType } /** - * append Choice on POST_SET_DATA event + * Return the root form (i.e. produced from CustomFieldsGroupType::getForm). * - * Choices are extracted from custom_field_group (the data associated - * with the root form) - * - * @param FormEvent $event - * @return void - */ - public function appendChoice(FormEvent $event) - { - $rootForm = $this->getRootForm($event->getForm()); - $group = $rootForm->getData(); - - if ($group === NULL) { - return; - } - - $choices = array(); - foreach($group->getCustomFields() as $customFields) { - $choices[$customFields->getSlug()] = - $this->translatableStringHelper - ->localize($customFields->getName()); - } - - $options = array_merge($this->options, array( - 'choices' => $choices, - )); - - $event->getForm()->getParent()->add($this->choiceName, ChoiceType::class, - $options); - } - - /** - * Return the root form (i.e. produced from CustomFieldsGroupType::getForm) - * - * @param FormInterface $form * @return FormInterface */ private function getRootForm(FormInterface $form) { - if ($form->getParent() === NULL) { + if ($form->getParent() === null) { return $form; - } else { - return $this->getRootForm($form->getParent()); } - } - public function getBlockPrefix() - { - return 'custom_fields_group_linked_custom_fields'; + return $this->getRootForm($form->getParent()); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/AppKernel.php b/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/AppKernel.php index d2e57ab94..554ed89e7 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/AppKernel.php +++ b/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/AppKernel.php @@ -1,39 +1,23 @@ load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - } - /** * @return string */ public function getCacheDir() { - return sys_get_temp_dir().'/CustomFieldsBundle/cache'; + return sys_get_temp_dir() . '/CustomFieldsBundle/cache'; } /** @@ -41,7 +25,29 @@ class AppKernel extends Kernel */ public function getLogDir() { - return $this->getRootDir().'/../logs'; + return $this->getRootDir() . '/../logs'; + } + + public function registerBundles() + { + return [ + new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), + new Chill\CustomFieldsBundle\ChillCustomFieldsBundle(), + new Symfony\Bundle\SecurityBundle\SecurityBundle(), + new Symfony\Bundle\MonologBundle\MonologBundle(), + new Symfony\Bundle\TwigBundle\TwigBundle(), + new \Symfony\Bundle\AsseticBundle\AsseticBundle(), + new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), + new \Chill\MainBundle\ChillMainBundle(), + new \Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(), + new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(), + new Chill\PersonBundle\ChillPersonBundle(), + //add here all the required bundle (some bundle are not required) + ]; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { + $loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml'); } } - diff --git a/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/autoload.php b/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/autoload.php index 39dc0e2ba..a2dfe7f92 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/autoload.php +++ b/src/Bundle/ChillCustomFieldsBundle/Resources/test/Fixtures/App/app/autoload.php @@ -1,11 +1,18 @@ loadClassCache(); diff --git a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldProvider.php b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldProvider.php index d2871560e..25e021f3c 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldProvider.php +++ b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldProvider.php @@ -1,103 +1,94 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Service; +use LogicException; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** * Receive all the services tagged with 'chill.custom_field'. - * + * * The services tagged with 'chill.custom_field' are services used to declare * a new custom field type. The tag must contain a 'type' variable (that must * be unique), this type is used to identify this custom field in the form - * declration - * + * declration + * * For example (in services.yml) : * services: * chill.icp2.type: * tags: * - { name: 'chill.custom_field', type: 'ICPC2' } - * - * @author Julien Fastré */ class CustomFieldProvider implements ContainerAwareInterface { - /** @var array $servicesByType The services indexes by the type */ - private $servicesByType = array(); - - /** @var Container $container The container */ - private $container; - /** - * Add a new custom field to the provider - * + * @var Container The container + */ + private $container; + + /** + * @var array The services indexes by the type + */ + private $servicesByType = []; + + /** + * Add a new custom field to the provider. + * * @param type $serviceName The name of the service (declared in service.yml) - * @param type $type The type of the service (that is used in the form to + * @param type $type The type of the service (that is used in the form to * add this type) */ public function addCustomField($serviceName, $type) { $this->servicesByType[$type] = $serviceName; } - - /** - * Get a custom field stored in the provider. The custom field is identified - * by its type. - * - * @param string $type The type of the wanted service - * @return CustomFieldInterface - */ - public function getCustomFieldByType($type) - { - if (isset($this->servicesByType[$type])) { - return $this->servicesByType[$type]; - } else { - throw new \LogicException('the custom field with type '.$type.' ' - . 'is not found'); - } - } - /* - * (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() - */ - public function setContainer(ContainerInterface $container = null) - { - if ($container === null) { - throw new \LogicException('container should not be null'); - } - - $this->container = $container; - } - /** - * Get all the custom fields known by the provider - * + * Get all the custom fields known by the provider. + * * @return array Array of the known custom fields indexed by the type. */ public function getAllFields() { return $this->servicesByType; } + + /** + * Get a custom field stored in the provider. The custom field is identified + * by its type. + * + * @param string $type The type of the wanted service + * + * @return CustomFieldInterface + */ + public function getCustomFieldByType($type) + { + if (isset($this->servicesByType[$type])) { + return $this->servicesByType[$type]; + } + + throw new LogicException('the custom field with type ' . $type . ' ' + . 'is not found'); + } + + /* + * (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() + */ + public function setContainer(?ContainerInterface $container = null) + { + if (null === $container) { + throw new LogicException('container should not be null'); + } + + $this->container = $container; + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelper.php b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelper.php index f5bc2cc2e..e32a35cee 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelper.php +++ b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelper.php @@ -1,90 +1,77 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Service; -use Doctrine\ORM\EntityManagerInterface; -use Chill\CustomFieldsBundle\Service\CustomFieldProvider; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\CustomFieldsBundle\Entity\CustomField; +use Doctrine\ORM\EntityManagerInterface; /** * Helpers for manipulating custom fields. - * + * * Herlpers for getting a certain custom field, for getting the raw value * of a custom field and for rendering the value of a custom field. - * - * @author Julien Fastré - * */ class CustomFieldsHelper { - /** @var EntityManagerInterface $em The entity manager */ + /** + * @var EntityManagerInterface The entity manager + */ private $em; - - /** @var CustomFieldProvider $provider Provider of all the declared custom + + /** @var CustomFieldProvider Provider of all the declared custom * fields */ private $provider; - + /** - * Constructor - * + * Constructor. + * * @param EntityManagerInterface $em The entity manager - * @param CustomFieldProvider $provider The customfield provider that + * @param CustomFieldProvider $provider The customfield provider that * contains all the declared custom fields */ - public function __construct(EntityManagerInterface $em, - CustomFieldProvider $provider) - { + public function __construct( + EntityManagerInterface $em, + CustomFieldProvider $provider + ) { $this->em = $em; $this->provider = $provider; } - + public function isEmptyValue(array $fields, CustomField $customField) { $slug = $customField->getSlug(); $rawValue = (isset($fields[$slug])) ? $fields[$slug] : null; - $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); - + $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); + $deserializedValue = $customFieldType->deserialize($rawValue, $customField); - + return $customFieldType->isEmptyValue($deserializedValue, $customField); } - + /** - * Render the value of a custom field - * + * Render the value of a custom field. + * * @param array $fields the **raw** array, as stored in the db * @param CustomField $customField the customField entity * @param string $documentType The type of document in which the rendered value is displayed ('html' or 'csv'). + * * @throws CustomFieldsHelperException if slug is missing + * * @return The representation of the value the customField. */ - public function renderCustomField(array $fields, CustomField $customField, $documentType='html') + public function renderCustomField(array $fields, CustomField $customField, $documentType = 'html') { $slug = $customField->getSlug(); $rawValue = (isset($fields[$slug])) ? $fields[$slug] : null; - $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); - + $customFieldType = $this->provider->getCustomFieldByType($customField->getType()); + return $customFieldType->render($rawValue, $customField, $documentType); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelperException.php b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelperException.php index 497c96720..88a40b58b 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelperException.php +++ b/src/Bundle/ChillCustomFieldsBundle/Service/CustomFieldsHelperException.php @@ -1,36 +1,25 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Service; -class CustomFieldsHelperException extends \Exception +use Exception; + +class CustomFieldsHelperException extends Exception { - public static function customFieldsGroupNotFound($entity) + public static function customFieldsGroupNotFound($entity) { - return new CustomFieldsHelperException("The customFieldsGroups associated with $entity are not found"); + return new CustomFieldsHelperException("The customFieldsGroups associated with {$entity} are not found"); } - + public static function slugIsMissing() { - return new CustomFieldsHelperException("The slug is missing"); + return new CustomFieldsHelperException('The slug is missing'); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldRenderingTwig.php b/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldRenderingTwig.php index abbbace5d..9f0e94940 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldRenderingTwig.php +++ b/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldRenderingTwig.php @@ -1,72 +1,51 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Templating\Twig; +use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\Service\CustomFieldsHelper; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Container; -use Chill\CustomFieldsBundle\Entity\CustomField; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; /** * Add the following Twig Extension : * * chill_custom_field_widget : to render the value of the custom field, - * * chill_custom_field_label : to render the label of the custom field, - * - * @author Julien Fastré + * * chill_custom_field_label : to render the label of the custom field,. */ class CustomFieldRenderingTwig extends AbstractExtension implements ContainerAwareInterface { - - /** @var Container $container The container */ + /** + * @var Container The container + */ private $container; - - /** @var array $defaultParams The default parameters */ - private $defaultParams = array( - 'label_layout' => 'ChillCustomFieldsBundle:CustomField:render_label.html.twig' - ); - + /** * @var CustomFieldsHelper */ private $customFieldsHelper; - + + /** + * @var array The default parameters + */ + private $defaultParams = [ + 'label_layout' => 'ChillCustomFieldsBundle:CustomField:render_label.html.twig', + ]; + public function __construct(CustomFieldsHelper $customFieldsHelper) { $this->customFieldsHelper = $customFieldsHelper; } - - /* - * (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() - */ - public function setContainer(ContainerInterface $container = null) - { - $this->container = $container; - } - + /* * (non-PHPdoc) * @see Twig_Extension::getFunctions() @@ -74,73 +53,82 @@ class CustomFieldRenderingTwig extends AbstractExtension implements ContainerAwa public function getFunctions() { return [ - new TwigFunction('chill_custom_field_widget', array( + new TwigFunction('chill_custom_field_widget', [ $this, - 'renderWidget' - ), array( - 'is_safe' => array( - 'html' - ) - )), - new TwigFunction('chill_custom_field_label', array( + 'renderWidget', + ], [ + 'is_safe' => [ + 'html', + ], + ]), + new TwigFunction('chill_custom_field_label', [ $this, - 'renderLabel' - ), array( - 'is_safe' => array( - 'html' - ) - )), - new TwigFunction('chill_custom_field_is_empty', array( + 'renderLabel', + ], [ + 'is_safe' => [ + 'html', + ], + ]), + new TwigFunction('chill_custom_field_is_empty', [ $this, - 'isEmptyValue' - )) + 'isEmptyValue', + ]), ]; } - - + + /* (non-PHPdoc) + * @see Twig_ExtensionInterface::getName() + */ + public function getName() + { + return 'chill_custom_fields_rendering'; + } + public function isEmptyValue($fields, CustomField $customField) { return $this->customFieldsHelper ->isEmptyValue($fields, $customField); } - - /* (non-PHPdoc) - * @see Twig_ExtensionInterface::getName() - */ - public function getName() - { - return 'chill_custom_fields_rendering'; - } /** * Twig Extension that is used to render the label of a custom field. - * + * * @param CustomField $customField Either a customField OR a customizable_entity OR the FQDN of the entity * @param array $params The parameters for rendering. Currently, 'label_layout' allow to choose a different label. Default is 'ChillCustomFieldsBundle:CustomField:render_label.html.twig' + * * @return string HTML representation of the custom field label. */ - public function renderLabel(CustomField $customField, array $params = array()) + public function renderLabel(CustomField $customField, array $params = []) { $resolvedParams = array_merge($this->defaultParams, $params); - + return $this->container->get('templating') - ->render($resolvedParams['label_layout'], array('customField' => $customField)); + ->render($resolvedParams['label_layout'], ['customField' => $customField]); } - + /** * Twig extension that is used to render the value of a custom field. - * + * * The presentation of the value is influenced by the document type. - * + * * @param array $fields The array raw, as stored in the db * @param CustomField $customField Either a customField OR a customizable_entity OR the FQDN of the entity * @param string $documentType The type of the document (csv, html) - * @param string $slug The slug of the custom field ONLY necessary if the first argument is NOT a CustomField instance + * * @return string HTML representation of the custom field value, as described in the CustomFieldInterface. Is HTML safe */ - public function renderWidget(array $fields, CustomField $customField, $documentType='html') + public function renderWidget(array $fields, CustomField $customField, $documentType = 'html') { return $this->customFieldsHelper ->renderCustomField($fields, $customField, $documentType); } -} \ No newline at end of file + + /* + * (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() + */ + public function setContainer(?ContainerInterface $container = null) + { + $this->container = $container; + } +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldsGroupRenderingTwig.php b/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldsGroupRenderingTwig.php index 10758d26d..1de69e15a 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldsGroupRenderingTwig.php +++ b/src/Bundle/ChillCustomFieldsBundle/Templating/Twig/CustomFieldsGroupRenderingTwig.php @@ -1,71 +1,48 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Templating\Twig; +use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Container; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; /** * Add the following Twig Extension : * * chill_custom_fields_group_widget : to render the value of a custom field - * * group - * - * @author Julien Fastré - * @author Marc Ducobu + * * group. */ class CustomFieldsGroupRenderingTwig extends AbstractExtension implements ContainerAwareInterface { - - /** @var Container $container The container */ - private $container; - - /** @var array $defaultParams The default parameters */ - private $defaultParams = array( - 'layout' => 'ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig', - 'show_empty' => True - ); - /** - * - * @param boolean $showEmptyValues whether the empty values must be rendered + * @var Container The container + */ + private $container; + + /** + * @var array The default parameters + */ + private $defaultParams = [ + 'layout' => 'ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig', + 'show_empty' => true, + ]; + + /** + * @param bool $showEmptyValues whether the empty values must be rendered */ public function __construct($showEmptyValues) { $this->defaultParams['show_empty'] = $showEmptyValues; } - - /* - * (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() - */ - public function setContainer(ContainerInterface $container = null) - { - $this->container = $container; - } - + /* * (non-PHPdoc) * @see Twig_Extension::getFunctions() @@ -73,48 +50,58 @@ class CustomFieldsGroupRenderingTwig extends AbstractExtension implements Contai public function getFunctions() { return [ - new TwigFunction('chill_custom_fields_group_widget', array( + new TwigFunction('chill_custom_fields_group_widget', [ $this, - 'renderWidget' - ), array( - 'is_safe' => array( - 'html' - ) - )), + 'renderWidget', + ], [ + 'is_safe' => [ + 'html', + ], + ]), ]; } - + /* (non-PHPdoc) * @see Twig_ExtensionInterface::getName() */ - public function getName() + public function getName() { return 'chill_custom_fields_group_rendering'; } - + /** * Twig extension that is used to render the value of a custom field group. - * + * * The presentation of the value is influenced by the document type. - * + * * @param array $fields The array raw, as stored in the db * @param CustomFieldsGroud $customFielsGroup The custom field group * @param string $documentType The type of the document (csv, html) - * @param array $params The parameters for rendering : + * @param array $params The parameters for rendering : * - layout : allow to choose a different layout by default : * ChillCustomFieldsBundle:CustomFieldsGroup:render.html.twig * - show_empty : force show empty field - * @return string HTML representation of the custom field group value, as described in + * + * @return string HTML representation of the custom field group value, as described in * the CustomFieldInterface. Is HTML safe */ - public function renderWidget(array $fields, $customFielsGroup, $documentType='html', array $params = array()) + public function renderWidget(array $fields, $customFielsGroup, $documentType = 'html', array $params = []) { $resolvedParams = array_merge($this->defaultParams, $params); - + return $this->container->get('templating') - ->render($resolvedParams['layout'], array( - 'cFGroup' => $customFielsGroup, - 'cFData' => $fields, - 'show_empty' => $resolvedParams['show_empty'])); + ->render($resolvedParams['layout'], [ + 'cFGroup' => $customFielsGroup, + 'cFData' => $fields, + 'show_empty' => $resolvedParams['show_empty'], ]); } -} \ No newline at end of file + + /* + * (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\ContainerAwareInterface::setContainer() + */ + public function setContainer(?ContainerInterface $container = null) + { + $this->container = $container; + } +} diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Config/ConfigCustomizablesEntitiesTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Config/ConfigCustomizablesEntitiesTest.php index df66ab56c..cee8dfd50 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Config/ConfigCustomizablesEntitiesTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Config/ConfigCustomizablesEntitiesTest.php @@ -1,21 +1,10 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests\Config; @@ -23,48 +12,49 @@ namespace Chill\CustomFieldsBundle\Tests\Config; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** - * Test the option Customizables_entities + * Test the option Customizables_entities. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ConfigCustomizablesEntitiesTest extends KernelTestCase { - /** - * Test that the config does work if the option - * chill_custom_fields.customizables_entities IS NOT present - * - * In this case, parameter 'chill_custom_fields.customizables_entities' - * should be an empty array in container - */ - public function testNotPresentInConfig() - { - self::bootKernel(array('environment' => 'test')); - $customizableEntities = static::$kernel->getContainer() - ->getParameter('chill_custom_fields.customizables_entities'); - - $this->assertInternalType('array', $customizableEntities); - $this->assertCount(1, $customizableEntities); - } - /** * Test that the 'chill_custom_fields.customizables_entities' is filled * correctly with a minimal configuration. - * + * * @internal use a custom config environment */ public function testNotEmptyConfig() { - self::bootKernel(array('environment' => 'test_customizable_entities_test_not_empty_config')); + self::bootKernel(['environment' => 'test_customizable_entities_test_not_empty_config']); $customizableEntities = static::$kernel->getContainer() - ->getParameter('chill_custom_fields.customizables_entities'); - + ->getParameter('chill_custom_fields.customizables_entities'); + $this->assertInternalType('array', $customizableEntities); $this->assertCount(2, $customizableEntities); - - foreach($customizableEntities as $key => $config) { + + foreach ($customizableEntities as $key => $config) { $this->assertInternalType('array', $config); $this->assertArrayHasKey('name', $config); $this->assertArrayHasKey('class', $config); } } + + /** + * Test that the config does work if the option + * chill_custom_fields.customizables_entities IS NOT present. + * + * In this case, parameter 'chill_custom_fields.customizables_entities' + * should be an empty array in container + */ + public function testNotPresentInConfig() + { + self::bootKernel(['environment' => 'test']); + $customizableEntities = static::$kernel->getContainer() + ->getParameter('chill_custom_fields.customizables_entities'); + + $this->assertInternalType('array', $customizableEntities); + $this->assertCount(1, $customizableEntities); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldControllerTest_TODO.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldControllerTest_TODO.php index c41de20e0..b88f0b6a5 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldControllerTest_TODO.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldControllerTest_TODO.php @@ -1,9 +1,20 @@ assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldsGroupControllerTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldsGroupControllerTest.php index 8822aec15..b9bb5c785 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldsGroupControllerTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Controller/CustomFieldsGroupControllerTest.php @@ -1,21 +1,31 @@ 'test_customizable_entities_test_not_empty_config')); + self::bootKernel(['environment' => 'test_customizable_entities_test_not_empty_config']); // Create a new client to browse the application - $client = static::createClient(array(), array( + $client = static::createClient([], [ 'PHP_AUTH_USER' => 'admin', - 'PHP_AUTH_PW' => 'olala', - )); + 'PHP_AUTH_PW' => 'olala', + ]); //create the entity $this->createCustomFieldsGroup($client); @@ -28,47 +38,59 @@ class CustomFieldsGroupControllerTest extends WebTestCase { // Create a new entry in the database $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); - - $this->assertEquals(200, $client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /customfieldsgroup/"); + + $this->assertEquals( + 200, + $client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /customfieldsgroup/' + ); $crawler = $client->click($crawler->selectLink('Créer un nouveau groupe')->link()); - + // Fill in the form and submit it - $form = $crawler->selectButton('Créer')->form(array( - 'custom_fields_group[name][fr]' => 'Test', - 'custom_fields_group[entity]' => 'Chill\PersonBundle\Entity\Person' - )); + $form = $crawler->selectButton('Créer')->form([ + 'custom_fields_group[name][fr]' => 'Test', + 'custom_fields_group[entity]' => 'Chill\PersonBundle\Entity\Person', + ]); $crawler = $client->submit($form); - + $crawler = $client->followRedirect(); // Check data in the show view - $this->assertGreaterThan(0, $crawler->filter('td:contains("Test")')->count(), - 'Missing element td:contains("Test")'); + $this->assertGreaterThan( + 0, + $crawler->filter('td:contains("Test")')->count(), + 'Missing element td:contains("Test")' + ); } - + private function editCustomFieldsGroup(Client $client) { $crawler = $client->request('GET', '/fr/admin/customfieldsgroup/'); $links = $crawler->selectLink('Modifier'); - - $this->assertGreaterThan(0, $links->count(), - "We can't find a 'Modifier' link on the index page"); + + $this->assertGreaterThan( + 0, + $links->count(), + "We can't find a 'Modifier' link on the index page" + ); $crawler = $client->click($links->last()->link()); $this->assertEquals(200, $client->getResponse()->getStatusCode()); - - $form = $crawler->selectButton('Mettre à jour')->form(array( - 'custom_fields_group[name][fr]' => 'Foo', - )); + + $form = $crawler->selectButton('Mettre à jour')->form([ + 'custom_fields_group[name][fr]' => 'Foo', + ]); $client->submit($form); $crawler = $client->followRedirect(); // Check the element contains an attribute with value equals "Foo" - $this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), - 'Missing element [value="Foo"]'); + $this->assertGreaterThan( + 0, + $crawler->filter('[value="Foo"]')->count(), + 'Missing element [value="Foo"]' + ); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFieldTestHelper.php b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFieldTestHelper.php index 3d4c58fe0..c608b7a65 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFieldTestHelper.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFieldTestHelper.php @@ -1,86 +1,71 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Chill\CustomFieldsBundle\Entity\CustomField; -use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\DomCrawler\Crawler; /** - * Give useful method to prepare tests regarding custom fields - * - * @author Julien Fastré + * Give useful method to prepare tests regarding custom fields. */ trait CustomFieldTestHelper { - /** - * Prepare a crawler containing the rendering of a customField - * + * Prepare a crawler containing the rendering of a customField. + * * @internal This method will mock a customFieldGroup containing $field, and * rendering the customfield, using Type\CustomFieldType, to a simple form row - * - * @param CustomField $field - * @param KernelTestCase $testCase - * @param KernelInterface $kernel + * * @param type $locale + * * @return Crawler */ public function getCrawlerForField(CustomField $field, $locale = 'en') { $kernel = static::$kernel; - + //check a kernel is accessible $customFieldsGroup = $this->createMock('Chill\CustomFieldsBundle\Entity\CustomFieldsGroup'); $customFieldsGroup->expects($this->once()) ->method('getActiveCustomFields') - ->will($this->returnValue(array($field))); - + ->will($this->returnValue([$field])); + $request = $this->createMock('Symfony\Component\HttpFoundation\Request'); $request->expects($this->any()) ->method('getLocale') ->will($this->returnValue($locale)); $kernel->getContainer()->get('request_stack')->push($request); - + $builder = $kernel->getContainer()->get('form.factory')->createBuilder(); - $form = $builder->add('tested', 'custom_field', - array('group' => $customFieldsGroup)) + $form = $builder->add( + 'tested', + 'custom_field', + ['group' => $customFieldsGroup] + ) ->getForm(); - + $kernel->getContainer()->get('twig.loader') - ->addPath($kernel->getContainer()->getParameter('kernel.root_dir'). + ->addPath($kernel->getContainer()->getParameter('kernel.root_dir') . '/Resources/views/', $namespace = 'test'); $content = $kernel ->getContainer()->get('templating') - ->render('@test/CustomField/simple_form_render.html.twig', array( + ->render('@test/CustomField/simple_form_render.html.twig', [ 'form' => $form->createView(), - 'inputKeys' => array('tested') - )); + 'inputKeys' => ['tested'], + ]); $crawler = new Crawler(); $crawler->addHtmlContent($content); - + return $crawler; } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsChoiceTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsChoiceTest.php index 28351711c..815e529bb 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsChoiceTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsChoiceTest.php @@ -1,69 +1,443 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** * This class cover the test of CustomFieldChoice. - * - * Function currently covered: - * + * + * Function currently covered: + * * - deserialize * - * @author Julien Fastré + * @internal + * @coversNothing */ class CustomFieldsChoiceTest extends KernelTestCase { - /** - * - * @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider - */ - private $cfProvider; - - /** - * * @var \Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice */ private $cfChoice; - + + /** + * @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider + */ + private $cfProvider; + public function setUp() { static::bootKernel(); - + $this->cfProvider = static::$kernel->getContainer() - ->get('chill.custom_field.provider'); + ->get('chill.custom_field.provider'); $this->cfChoice = $this->cfProvider->getCustomFieldByType('choice'); } - + public function tearDown() { parent::tearDown(); } - + + /** + * provide empty data in different possible representations. + * Those data are supposed to be deserialized. + * + * @return array + */ + public function emptyDataProvider() + { + return [ + // 0 + [ + // signle + '', + ], + // 1 + [ + // single + null, + ], + // 2 + [ + // signle with allow other + ['_other' => 'something', '_choices' => ''], + ], + // 3 + [ + // multiple + [], + ], + // 4 + [ + // multiple with allow other + ['_other' => 'something', '_choices' => []], + ], + // 5 + [ + // multiple with allow other + ['_other' => '', '_choices' => []], + ], + // 6 + [ + // empty + ['_other' => null, '_choices' => null], + ], + // 7 + [ + // empty + [null], + ], + ]; + } + + public function serializedRepresentationDataProvider() + { + return [ + [ + // multiple => false, allow_other => false + 'my-value', + ], + [ + // multiple => true, allow_ther => false + ['my-value'], + ], + [ + // multiple => false, allow_other => true, current value not in other + ['_other' => '', '_choices' => 'my-value'], + ], + [ + // multiple => true, allow_other => true, current value not in other + ['_other' => '', '_choices' => ['my-value']], + ], + ]; + } + + /** + * Test if the representation of the data is deserialized to an array text + * with an "allow_other" field. + * + * This test does not covers the case when the selected value is `_other` + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeMultipleChoiceWithOther($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => true, + ]); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame( + ['_other' => '', '_choices' => ['my-value']], + $deserialized + ); + } + + /** + * Test if the representation of the data is deserialized to an array text + * with an "allow_other" field. + * + * This test covers : + * - the case when the selected value is `_other` + * - result is null + */ + public function testDeserializeMultipleChoiceWithOtherOtherCases() + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => true, + ]); + + // selected value is _other + // from single to multiple + $data = ['_other' => 'something', '_choices' => '_other']; + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame( + ['_other' => 'something', '_choices' => ['_other']], + $deserialized + ); + + // from multiple to multiple + $data = ['_other' => 'something', '_choices' => ['_other', 'something']]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame( + ['_other' => 'something', '_choices' => ['_other', 'something']], + $deserialized + ); + + // test with null value + // from single to multiple + $data = ['_other' => '', '_choices' => '']; + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame( + ['_other' => '', '_choices' => ['']], + $deserialized + ); + + // from multiple to multiple + $data = ['_other' => '', '_choices' => []]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame( + ['_other' => '', '_choices' => []], + $deserialized + ); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => null], $customField); + $this->assertSame(['_other' => '', '_choices' => [null]], $deserialized); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => ''], $customField); + $this->assertSame(['_other' => '', '_choices' => ['']], $deserialized); + + $deserialized = $this->cfChoice->deserialize([null], $customField); + $this->assertSame(['_other' => '', '_choices' => [null]], $deserialized); + } + + /** + * Test if the representation of the data is deserialized to an array text + * **without** an "allow_other" field. + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeMultipleChoiceWithoutOther($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true, + ]); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(['my-value'], $deserialized); + } + + /** + * Test if the representation of the data is deserialized to an array text + * **without** an "allow_other" field. + * + * Covered cases : + * - NULL values + */ + public function testDeserializeMultipleChoiceWithoutOtherOtherCases() + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true, + ]); + + // from single to multiple + $data = 'my-value'; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['my-value'], $deserialized); + + // from multiple to multiple + $data = ['my-value']; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['my-value'], $deserialized); + + // from multiple + $data = [null]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame([null], $deserialized); + + $data = ['_other' => null, '_choices' => [null]]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame([null], $deserialized); + + //from single + $data = ['_other' => null, '_choices' => null]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame([null], $deserialized); + } + + /** + * Test if the representation of the data is deserialized to a single text + * with an "allow_other" field. + * + * If the value is in _other, the _other value should be in the _other field. + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeSingleChoiceWithOther($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => false, + ]); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame(['_other' => '', '_choices' => 'my-value'], $deserialized); + } + + /** + * Other cases :. + * + * - Test if the selected value is '_other + * - Test with null data + */ + public function testDeserializeSingleChoiceWithOtherOtherCases() + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => true, + CustomFieldChoice::MULTIPLE => false, + ]); + + // from a single to a single + $data = ['_other' => 'something', '_choices' => '_other']; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => '_other'], $deserialized); + + // from a multiple to a single + $data = ['_other' => 'something', '_choices' => ['some', '_other']]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => '_other'], $deserialized); + + //test with null data + //from a single to a single : + $data = ['_other' => 'something', '_choices' => null]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => null], $deserialized); + + $data = ['_other' => 'something', '_choices' => '']; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => ''], $deserialized); + + // from a multiple to a signle + $data = ['_other' => 'something', '_choices' => []]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => ''], $deserialized); + + $data = ['_other' => 'something', '_choices' => ['']]; + $deserialized = $this->cfChoice->deserialize($data, $customField); + $this->assertSame(['_other' => 'something', '_choices' => ''], $deserialized); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => null], $customField); + $this->assertSame(['_other' => '', '_choices' => null], $deserialized); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => ''], $customField); + $this->assertSame(['_other' => '', '_choices' => ''], $deserialized); + + $deserialized = $this->cfChoice->deserialize([null], $customField); + $this->assertSame(['_other' => '', '_choices' => null], $deserialized); + } + + ///////////////////////////////////////// + // + // test function deserialize + // + //////////////////////////////////////// + + /** + * Test if the representation of the data is deserialized to a single text. + * + * If the value is in _other, the _other value should not be returned. + * + * @param type $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testDeserializeSingleChoiceWithoutOther($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => false, + ]); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + + $this->assertSame('my-value', $deserialized); + } + + public function testDeserializeSingleChoiceWithoutOtherDataIsNull() + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => false, + ]); + + $deserialized = $this->cfChoice->deserialize(null, $customField); + $this->assertSame(null, $deserialized); + + $deserialized = $this->cfChoice->deserialize('', $customField); + $this->assertSame('', $deserialized); + + $deserialized = $this->cfChoice->deserialize([null], $customField); + $this->assertSame(null, $deserialized); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => null], $customField); + $this->assertSame(null, $deserialized); + + $deserialized = $this->cfChoice->deserialize(['_other' => null, '_choices' => ''], $customField); + $this->assertSame('', $deserialized); + + $deserialized = $this->cfChoice->deserialize([null], $customField); + $this->assertSame(null, $deserialized); + } + + /** + * @dataProvider emptyDataProvider + * + * @param mixed $data deserialized data + */ + public function testIsEmptyValueEmpty($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true, + ]); + + $isEmpty = $this->cfChoice->isEmptyValue($data, $customField); + + $this->assertTrue($isEmpty); + } + + ///////////////////////////////////////// + // + // test function isEmptyValue + // + //////////////////////////////////////// + + /** + * test the not empty with the not-empty data provider. + * + * @param mixed $data + * @dataProvider serializedRepresentationDataProvider + */ + public function testIsEmptyValueNotEmpty($data) + { + $customField = $this->generateCustomField([ + CustomFieldChoice::ALLOW_OTHER => false, + CustomFieldChoice::MULTIPLE => true, + ]); + + $deserialized = $this->cfChoice->deserialize($data, $customField); + $isEmpty = $this->cfChoice->isEmptyValue($deserialized, $customField); + + $this->assertFalse($isEmpty); + } + /** - * * @param array $options + * * @return CustomField */ private function generateCustomField($options) @@ -72,397 +446,6 @@ class CustomFieldsChoiceTest extends KernelTestCase ->setActive(true) ->setSlug('slug') ->setOptions($options) - ->setType('choice') - ; + ->setType('choice'); } - - ///////////////////////////////////////// - // - // test function deserialize - // - //////////////////////////////////////// - - /** - * Test if the representation of the data is deserialized to a single text. - * - * If the value is in _other, the _other value should not be returned. - * - * @param type $data - * @dataProvider serializedRepresentationDataProvider - */ - public function testDeserializeSingleChoiceWithoutOther($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => false - )); - - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame('my-value', $deserialized); - } - - - public function testDeserializeSingleChoiceWithoutOtherDataIsNull() - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => false - )); - - $deserialized = $this->cfChoice->deserialize(null, $customField); - $this->assertSame(null, $deserialized); - - $deserialized = $this->cfChoice->deserialize('', $customField); - $this->assertSame('', $deserialized); - - $deserialized = $this->cfChoice->deserialize(array(null), $customField); - $this->assertSame(null, $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField); - $this->assertSame(null, $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField); - $this->assertSame('', $deserialized); - - $deserialized = $this->cfChoice->deserialize(array(null), $customField); - $this->assertSame(null, $deserialized); - } - - /** - * Test if the representation of the data is deserialized to a single text - * with an "allow_other" field. - * - * If the value is in _other, the _other value should be in the _other field. - * - * @param type $data - * @dataProvider serializedRepresentationDataProvider - */ - public function testDeserializeSingleChoiceWithOther($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => true, - CustomFieldChoice::MULTIPLE => false - )); - - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => '', '_choices' => 'my-value'), $deserialized); - } - - /** - * Other cases : - * - * - Test if the selected value is '_other - * - Test with null data - * - * @param type $data - */ - public function testDeserializeSingleChoiceWithOtherOtherCases() - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => true, - CustomFieldChoice::MULTIPLE => false - )); - - // from a single to a single - $data = array('_other' => 'something', '_choices' => '_other'); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => '_other'), $deserialized); - - - // from a multiple to a single - $data = array('_other' => 'something', '_choices' => array('some', '_other')); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => '_other'), $deserialized); - - //test with null data - //from a single to a single : - $data = array('_other' => 'something', '_choices' => null); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => null), $deserialized); - - $data = array('_other' => 'something', '_choices' => ''); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); - - // from a multiple to a signle - $data = array('_other' => 'something', '_choices' => array()); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); - - $data = array('_other' => 'something', '_choices' => array('')); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('_other' => 'something', '_choices' => ''), $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField); - $this->assertSame(array('_other' => '', '_choices' => null), $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField); - $this->assertSame(array('_other' => '', '_choices' => ''), $deserialized); - - $deserialized = $this->cfChoice->deserialize(array(null), $customField); - $this->assertSame(array('_other' => '', '_choices' => null), $deserialized); - - } - - /** - * Test if the representation of the data is deserialized to an array text - * with an "allow_other" field. - * - * This test does not covers the case when the selected value is `_other` - * - * @param type $data - * @dataProvider serializedRepresentationDataProvider - */ - public function testDeserializeMultipleChoiceWithOther($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => true, - CustomFieldChoice::MULTIPLE => true - )); - - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => '', '_choices' => array('my-value')), - $deserialized); - } - - /** - * Test if the representation of the data is deserialized to an array text - * with an "allow_other" field. - * - * This test covers : - * - the case when the selected value is `_other` - * - result is null - * - * @param type $data - */ - public function testDeserializeMultipleChoiceWithOtherOtherCases() - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => true, - CustomFieldChoice::MULTIPLE => true - )); - - // selected value is _other - // from single to multiple - $data = array('_other' => 'something', '_choices' => '_other'); - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => 'something', '_choices' => array('_other')), - $deserialized); - - // from multiple to multiple - $data = array('_other' => 'something', '_choices' => array('_other', 'something')); - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => 'something', '_choices' => array('_other', 'something')), - $deserialized); - - // test with null value - // from single to multiple - $data = array('_other' => '', '_choices' => ''); - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => '', '_choices' => array('')), - $deserialized); - - // from multiple to multiple - $data = array('_other' => '', '_choices' => array()); - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('_other' => '', '_choices' => array()), - $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => null), $customField); - $this->assertSame(array('_other' => '', '_choices' => array(null)), $deserialized); - - $deserialized = $this->cfChoice->deserialize(array('_other' => null, '_choices' => ''), $customField); - $this->assertSame(array('_other' => '', '_choices' => array('')), $deserialized); - - $deserialized = $this->cfChoice->deserialize(array(null), $customField); - $this->assertSame(array('_other' => '', '_choices' => array(null)), $deserialized); - } - - /** - * Test if the representation of the data is deserialized to an array text - * **without** an "allow_other" field. - * - * - * @param type $data - * @dataProvider serializedRepresentationDataProvider - */ - public function testDeserializeMultipleChoiceWithoutOther($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => true - )); - - $deserialized = $this->cfChoice->deserialize($data, $customField); - - $this->assertSame(array('my-value'), $deserialized); - } - - /** - * Test if the representation of the data is deserialized to an array text - * **without** an "allow_other" field. - * - * Covered cases : - * - NULL values - * - * - * @param type $data - */ - public function testDeserializeMultipleChoiceWithoutOtherOtherCases() - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => true - )); - - // from single to multiple - $data = 'my-value'; - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('my-value'), $deserialized); - - // from multiple to multiple - $data = array('my-value'); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array('my-value'), $deserialized); - - // from multiple - $data = array(null); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array(null), $deserialized); - - $data = array('_other' => null, '_choices' => array(null)); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array(null), $deserialized); - - //from single - $data = array('_other' => null, '_choices' => null); - $deserialized = $this->cfChoice->deserialize($data, $customField); - $this->assertSame(array(null), $deserialized); - } - - public function serializedRepresentationDataProvider() - { - return array( - array( - // multiple => false, allow_other => false - 'my-value' - ), - array( - // multiple => true, allow_ther => false - array('my-value') - ), - array( - // multiple => false, allow_other => true, current value not in other - array('_other' => '', '_choices' => 'my-value') - ), - array( - // multiple => true, allow_other => true, current value not in other - array('_other' => '', '_choices'=> array('my-value')) - ), - ); - } - - - - ///////////////////////////////////////// - // - // test function isEmptyValue - // - //////////////////////////////////////// - - /** - * test the not empty with the not-empty data provider - * - * @param mixed $data - * @dataProvider serializedRepresentationDataProvider - */ - public function testIsEmptyValueNotEmpty($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => true - )); - - $deserialized = $this->cfChoice->deserialize($data, $customField); - $isEmpty = $this->cfChoice->isEmptyValue($deserialized, $customField); - - $this->assertFalse($isEmpty); - } - - /** - * - * @dataProvider emptyDataProvider - * @param mixed $data deserialized data - */ - public function testIsEmptyValueEmpty($data) - { - $customField = $this->generateCustomField(array( - CustomFieldChoice::ALLOW_OTHER => false, - CustomFieldChoice::MULTIPLE => true - )); - - $isEmpty = $this->cfChoice->isEmptyValue($data, $customField); - - $this->assertTrue($isEmpty); - } - - /** - * provide empty data in different possible representations. - * Those data are supposed to be deserialized. - * - * @return array - */ - public function emptyDataProvider() - { - return array( - // 0 - array( - // signle - '' - ), - // 1 - array( - // single - null - ), - // 2 - array( - // signle with allow other - array('_other' => 'something', '_choices' => '') - ), - // 3 - array( - // multiple - array() - ), - // 4 - array( - // multiple with allow other - array('_other' => 'something', '_choices' => array()) - ), - // 5 - array( - // multiple with allow other - array('_other' => '', '_choices' => array()) - ), - // 6 - array( - // empty - array('_other' => null, '_choices' => null) - ), - // 7 - array( - // empty - array(null) - ) - ); - } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsNumberTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsNumberTest.php index a206be5c7..d7fc89859 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsNumberTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsNumberTest.php @@ -1,45 +1,32 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests; use Chill\CustomFieldsBundle\CustomFields\CustomFieldNumber; -use Symfony\Component\Form\FormBuilderInterface; use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; -use Chill\CustomFieldsBundle\Form\CustomFieldsGroupType; +use Symfony\Component\Form\FormBuilderInterface; /** - * Test CustomFieldsNumber + * Test CustomFieldsNumber. * - * @author Julien Fastré + * @internal + * @coversNothing */ class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase { /** - * * @var CustomFieldNumber */ private $customFieldNumber; /** - * * @var FormBuilderInterface */ private $formBuilder; @@ -49,26 +36,135 @@ class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTes self::bootKernel(); $this->customFieldNumber = self::$kernel->getContainer() - ->get('chill.custom_field.number'); + ->get('chill.custom_field.number'); $this->formBuilder = self::$kernel->getContainer() - ->get('form.factory') - ->createBuilder('form', null, array( - 'csrf_protection' => false, - 'csrf_field_name' => '_token' - )); + ->get('form.factory') + ->createBuilder('form', null, [ + 'csrf_protection' => false, + 'csrf_field_name' => '_token', + ]); $request = new \Symfony\Component\HttpFoundation\Request(); $request->setLocale('fr'); self::$kernel->getContainer() - ->get('request_stack') - ->push($request); + ->get('request_stack') + ->push($request); + } + + public function testCreateInvalidFormValueGreaterThanMaximum() + { + $cf = $this->createCustomFieldNumber([ + 'min' => null, + 'max' => 10, + 'scale' => null, + 'post_text' => null, + ]); + + $this->customFieldNumber->buildForm($this->formBuilder, $cf); + + $form = $this->formBuilder->getForm(); + + $form->submit(['default' => 100]); + + $this->assertTrue($form->isSynchronized()); + $this->assertFalse($form->isValid()); + $this->assertEquals(1, count($form['default']->getErrors())); + } + + public function testCreateInvalidFormValueLowerThanMinimum() + { + $cf = $this->createCustomFieldNumber([ + 'min' => 1000, + 'max' => null, + 'scale' => null, + 'post_text' => null, + ]); + + $this->customFieldNumber->buildForm($this->formBuilder, $cf); + + $form = $this->formBuilder->getForm(); + + $form->submit(['default' => 100]); + + $this->assertTrue($form->isSynchronized()); + $this->assertFalse($form->isValid()); + $this->assertEquals(1, count($form['default']->getErrors())); + } + + public function testCreateValidForm() + { + $cf = $this->createCustomFieldNumber([ + 'min' => null, + 'max' => null, + 'scale' => null, + 'post_text' => null, + ]); + + $this->customFieldNumber->buildForm($this->formBuilder, $cf); + + $form = $this->formBuilder->getForm(); + + $form->submit(['default' => 10]); + + $this->assertTrue($form->isSynchronized()); + $this->assertEquals(10, $form['default']->getData()); + } + + public function testRequiredFieldIsFalse() + { + $cf = $this->createCustomFieldNumber([ + 'min' => 1000, + 'max' => null, + 'scale' => null, + 'post_text' => null, + ]); + $cf->setRequired(false); + + $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) + ->addCustomField($cf); + + $form = static::$kernel->getContainer()->get('form.factory') + ->createBuilder(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, [], [ + 'group' => $cfGroup, + ]) + ->getForm(); + + $this->assertFalse( + $form['default']->isRequired(), + 'The field should not be required' + ); + } + + public function testRequiredFieldIsTrue() + { + $cf = $this->createCustomFieldNumber([ + 'min' => 1000, + 'max' => null, + 'scale' => null, + 'post_text' => null, + ]); + $cf->setRequired(true); + + $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) + ->addCustomField($cf); + + $form = static::$kernel->getContainer()->get('form.factory') + ->createBuilder(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, [], [ + 'group' => $cfGroup, + ]) + ->getForm(); + + $this->assertTrue( + $form['default']->isRequired(), + 'The field should be required' + ); } /** - * * @param mixed[] $options + * * @return CustomField */ private function createCustomFieldNumber($options) @@ -78,114 +174,7 @@ class CustomFieldsNumberTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTes ->setActive(true) ->setOrdering(10) ->setSlug('default') - ->setName(array('fr' => 'default')) + ->setName(['fr' => 'default']) ->setOptions($options); } - - public function testCreateValidForm() - { - $cf = $this->createCustomFieldNumber(array( - 'min' => null, - 'max' => null, - 'scale' => null, - 'post_text' => null - )); - - $this->customFieldNumber->buildForm($this->formBuilder, $cf); - - $form = $this->formBuilder->getForm(); - - $form->submit(array('default' => 10)); - - $this->assertTrue($form->isSynchronized()); - $this->assertEquals(10, $form['default']->getData()); - } - - public function testCreateInvalidFormValueGreaterThanMaximum() - { - $cf = $this->createCustomFieldNumber(array( - 'min' => null, - 'max' => 10, - 'scale' => null, - 'post_text' => null - )); - - $this->customFieldNumber->buildForm($this->formBuilder, $cf); - - $form = $this->formBuilder->getForm(); - - $form->submit(array('default' => 100)); - - $this->assertTrue($form->isSynchronized()); - $this->assertFalse($form->isValid()); - $this->assertEquals(1, count($form['default']->getErrors())); - } - - public function testCreateInvalidFormValueLowerThanMinimum() - { - $cf = $this->createCustomFieldNumber(array( - 'min' => 1000, - 'max' => null, - 'scale' => null, - 'post_text' => null - )); - - $this->customFieldNumber->buildForm($this->formBuilder, $cf); - - $form = $this->formBuilder->getForm(); - - $form->submit(array('default' => 100)); - - $this->assertTrue($form->isSynchronized()); - $this->assertFalse($form->isValid()); - $this->assertEquals(1, count($form['default']->getErrors())); - } - - public function testRequiredFieldIsFalse() - { - $cf = $this->createCustomFieldNumber(array( - 'min' => 1000, - 'max' => null, - 'scale' => null, - 'post_text' => null - )); - $cf->setRequired(false); - - $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) - ->addCustomField($cf); - - $form = static::$kernel->getContainer()->get('form.factory') - ->createBuilder(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, array(), array( - 'group' => $cfGroup - )) - ->getForm(); - - $this->assertFalse($form['default']->isRequired(), - "The field should not be required"); - } - - public function testRequiredFieldIsTrue() - { - $cf = $this->createCustomFieldNumber(array( - 'min' => 1000, - 'max' => null, - 'scale' => null, - 'post_text' => null - )); - $cf->setRequired(true); - - $cfGroup = (new \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup()) - ->addCustomField($cf); - - $form = static::$kernel->getContainer()->get('form.factory') - ->createBuilder(\Chill\CustomFieldsBundle\Form\Type\CustomFieldType::class, array(), array( - 'group' => $cfGroup - )) - ->getForm(); - - $this->assertTrue($form['default']->isRequired(), - "The field should be required"); - } - - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsTextTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsTextTest.php index ad031e4a1..a685bc426 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsTextTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/CustomFields/CustomFieldsTextTest.php @@ -1,106 +1,93 @@ . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\CustomFields\CustomFieldText; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\DomCrawler\Crawler; -use Chill\CustomFieldsBundle\Tests\CustomFieldTestHelper; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class CustomFieldsTextTest extends WebTestCase { + use CustomFieldTestHelper; + /** - * - * @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider + * @var \Chill\CustomFieldsBundle\Service\CustomFieldProvider */ private $customFieldProvider; - - use CustomFieldTestHelper; - + public function setUp() { static::bootKernel(); $this->customFieldProvider = static::$kernel->getContainer() ->get('chill.custom_field.provider'); } - + public function testCustomFieldsTextExists() { $customField = $this->customFieldProvider->getCustomFieldByType('text'); - - $this->assertInstanceOf('Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface', - $customField); - $this->assertInstanceOf('Chill\CustomFieldsBundle\CustomFields\CustomFieldText', - $customField); + + $this->assertInstanceOf( + 'Chill\CustomFieldsBundle\CustomFields\CustomFieldInterface', + $customField + ); + $this->assertInstanceOf( + 'Chill\CustomFieldsBundle\CustomFields\CustomFieldText', + $customField + ); } - + + public function testFormTextNew() + { + $client = static::createClient(); + + $crawler = $client->request('GET', '/fr/admin/customfield/new?type=text'); + + $this->assertTrue($client->getResponse()->isSuccessful()); + + $form = $crawler->selectButton('custom_field_choice_submit')->form(); + $this->assertTrue($form->has('custom_field_choice[options][maxLength]')); + } + public function testPublicFormRenderingLengthLessThan256() { $customField = new CustomField(); $customField->setType('text') - ->setOptions(array(CustomFieldText::MAX_LENGTH => 255)) + ->setOptions([CustomFieldText::MAX_LENGTH => 255]) ->setSlug('slug') ->setOrdering(10) ->setActive(true) - ->setName(array('en' => 'my label')); - + ->setName(['en' => 'my label']); + $crawler = $this->getCrawlerForField($customField); - - $this->assertCount(1, $crawler->filter("input[type=text]")); - $this->assertCount(1, $crawler->filter("label:contains('my label')")); + + $this->assertCount(1, $crawler->filter('input[type=text]')); + $this->assertCount(1, $crawler->filter("label:contains('my label')")); } - + public function testPublicFormRenderingLengthMoreThan25() { $customField = new CustomField(); $customField->setType('text') - ->setOptions(array(CustomFieldText::MAX_LENGTH => 256)) + ->setOptions([CustomFieldText::MAX_LENGTH => 256]) ->setSlug('slug') ->setOrdering(10) ->setActive(true) - ->setName(array('en' => 'my label')); - + ->setName(['en' => 'my label']); + $crawler = $this->getCrawlerForField($customField); - - $this->assertCount(1, $crawler->filter("textarea")); - $this->assertCount(1, $crawler->filter("label:contains('my label')")); + + $this->assertCount(1, $crawler->filter('textarea')); + $this->assertCount(1, $crawler->filter("label:contains('my label')")); } - - public function testFormTextNew() - { - $client = static::createClient(); - - $crawler = $client->request('GET', '/fr/admin/customfield/new?type=text'); - - $this->assertTrue($client->getResponse()->isSuccessful()); - - $form = $crawler->selectButton('custom_field_choice_submit')->form(); - $this->assertTrue($form->has('custom_field_choice[options][maxLength]')); - } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextIntegerExtensionTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextIntegerExtensionTest.php index 5f395abe5..5bcb621d8 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextIntegerExtensionTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextIntegerExtensionTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFields\Tests\Form\Extension; @@ -23,14 +13,14 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Form\Extension\Core\Type\IntegerType; /** - * Test the post-text extension + * Test the post-text extension. * - * @author Julien Fastré + * @internal + * @coversNothing */ class PostTextIntegerExtensionTest extends KernelTestCase { /** - * * @var \Symfony\Component\Form\FormBuilderInterface */ private $formBuilder; @@ -42,18 +32,17 @@ class PostTextIntegerExtensionTest extends KernelTestCase $container = self::$kernel->getContainer(); $this->formBuilder = $container->get('form.factory') - ->createBuilder('form', null); + ->createBuilder('form', null); } public function testCreateView() { - $form = $this->formBuilder->add('test', IntegerType::class, array( - 'post_text' => 'my text' - ))->getForm(); + $form = $this->formBuilder->add('test', IntegerType::class, [ + 'post_text' => 'my text', + ])->getForm(); $view = $form->createView(); $this->assertEquals('my text', $view['test']->vars['post_text']); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextNumberExtensionTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextNumberExtensionTest.php index 86098ac21..c5c7ea9c3 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextNumberExtensionTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Form/Extension/PostTextNumberExtensionTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFields\Tests\Form\Extension; @@ -23,14 +13,14 @@ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Form\Extension\Core\Type\NumberType; /** - * Test the post-text extension + * Test the post-text extension. * - * @author Julien Fastré + * @internal + * @coversNothing */ class PostTextNumberExtensionTest extends KernelTestCase { /** - * * @var \Symfony\Component\Form\FormBuilderInterface */ private $formBuilder; @@ -42,18 +32,17 @@ class PostTextNumberExtensionTest extends KernelTestCase $container = self::$kernel->getContainer(); $this->formBuilder = $container->get('form.factory') - ->createBuilder('form', null); + ->createBuilder('form', null); } public function testCreateView() { - $form = $this->formBuilder->add('test', NumberType::class, array( - 'post_text' => 'my text' - ))->getForm(); + $form = $this->formBuilder->add('test', NumberType::class, [ + 'post_text' => 'my text', + ])->getForm(); $view = $form->createView(); $this->assertEquals('my text', $view['test']->vars['post_text']); } - } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Routing/RoutingLoaderTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Routing/RoutingLoaderTest.php index 290cce37b..748a79851 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Routing/RoutingLoaderTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Routing/RoutingLoaderTest.php @@ -1,21 +1,10 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFieldsBundle\Tests; @@ -24,22 +13,22 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Response; /** - * Test that routes are correctly loaded + * Test that routes are correctly loaded. * - * @author Julien Fastré + * @internal + * @coversNothing */ class RoutingLoaderTest extends WebTestCase { public function testRoutesAreLoaded() { $client = static::createClient(); - - $client->request('GET','/fr/admin/customfield/'); - + + $client->request('GET', '/fr/admin/customfield/'); + $this->assertEquals( Response::HTTP_OK, $client->getResponse()->getStatusCode() ); - } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Service/CustomFieldsHelperTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Service/CustomFieldsHelperTest.php index fc7276cf7..7b11b8c62 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Service/CustomFieldsHelperTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Service/CustomFieldsHelperTest.php @@ -1,92 +1,77 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFields\Tests\Service; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\CustomFieldsBundle\Service\CustomFieldsHelper; use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Service\CustomFieldsHelper; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** - * Tests for custom fields helper + * Tests for custom fields helper. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class CustomFieldsHelperTest extends KernelTestCase { /** - * * @var CustomFieldsHelper */ private $cfHelper; - + /** - * * @var CustomField */ private $randomCFText; - + public function setUp() { self::bootKernel(); - + $container = self::$kernel->getContainer(); - + $this->cfHelper = $container->get('chill.custom_field.helper'); - + $this->randomCFText = (new CustomField()) - ->setSlug('my-slug') - ->setActive(true) - ->setName(array('fr' => 'my cf')) - ->setOptions(array('maxLength' => 1000)) - ->setType('text') - ; + ->setSlug('my-slug') + ->setActive(true) + ->setName(['fr' => 'my cf']) + ->setOptions(['maxLength' => 1000]) + ->setType('text'); } - - public function testRenderCustomField() - { - $data = array( - $this->randomCFText->getSlug() => 'Sample text' - ); - - $text = $this->cfHelper->renderCustomField($data, $this->randomCFText); - - $this->assertContains('Sample text', $text); - } - + public function testIsEmptyValue() { // not empty value - $data = array( - $this->randomCFText->getSlug() => 'Sample text' - ); - + $data = [ + $this->randomCFText->getSlug() => 'Sample text', + ]; + $this->assertFalse($this->cfHelper->isEmptyValue($data, $this->randomCFText)); - + //empty value - $data = array( - $this->randomCFText->getSlug() => '' - ); - + $data = [ + $this->randomCFText->getSlug() => '', + ]; + $this->assertTrue($this->cfHelper->isEmptyValue($data, $this->randomCFText)); } - + + public function testRenderCustomField() + { + $data = [ + $this->randomCFText->getSlug() => 'Sample text', + ]; + + $text = $this->cfHelper->renderCustomField($data, $this->randomCFText); + + $this->assertContains('Sample text', $text); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php index 2f6f51df7..90a024414 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldRenderingTwigTest.php @@ -1,128 +1,118 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFields\Tests\Templating\Twig; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldRenderingTwig; use Chill\CustomFieldsBundle\Entity\CustomField; use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldRenderingTwig; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** - * Test the rendering of twig function which renders custom fields + * Test the rendering of twig function which renders custom fields. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class CustomFieldRenderingTwigTest extends KernelTestCase { /** - * - * @var CustomFieldRenderingTwig - */ - private $cfRendering; - - /** - * * @var CustomFieldProvider */ private $cfProvider; - + + /** + * @var CustomFieldRenderingTwig + */ + private $cfRendering; + public function setUp() { self::bootKernel(); $this->cfRendering = self::$kernel->getContainer() - ->get('chill.custom_field.twig.custom_fields_rendering') - ; - + ->get('chill.custom_field.twig.custom_fields_rendering'); + $this->cfProvider = self::$kernel->getContainer() - ->get('chill.custom_field.provider'); - + ->get('chill.custom_field.provider'); + // set locale to fr - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend('Symfony\Component\HttpFoundation\Request'); $request->getLocale()->willReturn('fr'); self::$kernel->getContainer()->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - + + public function testIsEmpty() + { + $cf = $this->getSimpleCustomFieldText(); + + // value is not empty + $fields = [ + 'test' => 'My tailor is rich', + ]; + + $result = $this->cfRendering->isEmptyValue($fields, $cf); + + $this->assertFalse($result); + + // value is empty + $fields = [ + 'text' => '', + ]; + + $result = $this->cfRendering->isEmptyValue($fields, $cf); + + $this->assertTrue($result); + } + + public function testLabelRendering() + { + $cf = $this->getSimpleCustomFieldText(); + + $text = $this->cfRendering->renderLabel($cf); + + $this->assertContains( + 'Test', + $text, + "The rendering text should contains the 'test' text" + ); + } + + public function testWidgetRendering() + { + $cf = $this->getSimpleCustomFieldText(); + $fields = [ + 'test' => 'My tailor is rich', + ]; + + $text = $this->cfRendering->renderWidget($fields, $cf); + + $this->assertContains( + 'My tailor is rich', + $text, + "The rendering text should contains the 'test' text" + ); + } + /** - * * @return CustomField */ private function getSimpleCustomFieldText() { return (new CustomField()) ->setSlug('test') - ->setName(array('fr' => 'Test')) - ->setType('text') - ->setOrdering(10) - ->setOptions(array("maxLength" => 255)) - ->setActive(true) - ; - } - - public function testLabelRendering() - { - $cf = $this->getSimpleCustomFieldText(); - - $text = $this->cfRendering->renderLabel($cf); - - $this->assertContains('Test', $text, - "The rendering text should contains the 'test' text"); - } - - public function testWidgetRendering() - { - $cf = $this->getSimpleCustomFieldText(); - $fields = array( - 'test' => "My tailor is rich" - ); - - $text = $this->cfRendering->renderWidget($fields, $cf); - - $this->assertContains('My tailor is rich', $text, - "The rendering text should contains the 'test' text"); - } - - public function testIsEmpty() - { - $cf = $this->getSimpleCustomFieldText(); - - // value is not empty - $fields = array( - 'test' => "My tailor is rich" - ); - - $result = $this->cfRendering->isEmptyValue($fields, $cf); - - $this->assertFalse($result); - - // value is empty - $fields = array( - 'text' => '' - ); - - $result = $this->cfRendering->isEmptyValue($fields, $cf); - - $this->assertTrue($result); + ->setName(['fr' => 'Test']) + ->setType('text') + ->setOrdering(10) + ->setOptions(['maxLength' => 255]) + ->setActive(true); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldsGroupRenderingTwigTest.php b/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldsGroupRenderingTwigTest.php index d1cbe0209..5636439b5 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldsGroupRenderingTwigTest.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/Templating/Twig/CustomFieldsGroupRenderingTwigTest.php @@ -1,130 +1,115 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\CustomFields\Tests\Templating\Twig; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldsGroupRenderingTwig; use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\CustomFieldsBundle\Service\CustomFieldProvider; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\CustomFieldsBundle\Templating\Twig\CustomFieldsGroupRenderingTwig; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** * Test the rendering of a custom fields group through - * the `chill_custom_fields_group_widget` + * the `chill_custom_fields_group_widget`. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class CustomFieldsGroupRenderingTwigTest extends KernelTestCase { /** - * - * @var CustomFieldsGroupRenderingTwig - */ - private $cfRendering; - - /** - * * @var CustomFieldProvider */ private $cfProvider; - + + /** + * @var CustomFieldsGroupRenderingTwig + */ + private $cfRendering; + public function setUp() { self::bootKernel(); $this->cfRendering = self::$kernel->getContainer() - ->get('chill.custom_field.twig.custom_fields_group_rendering') - ; - + ->get('chill.custom_field.twig.custom_fields_group_rendering'); + $this->cfProvider = self::$kernel->getContainer() - ->get('chill.custom_field.provider'); - + ->get('chill.custom_field.provider'); + // set locale to fr - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend('Symfony\Component\HttpFoundation\Request'); $request->getLocale()->willReturn('fr'); self::$kernel->getContainer()->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - - /** - * - * @return CustomField - */ - private function getSimpleCustomFieldText($slug, $name) - { - return (new CustomField()) - ->setSlug($slug) - ->setName(array('fr' => $name)) - ->setType('text') - ->setOrdering(10) - ->setOptions(array("maxLength" => 255)) - ->setActive(true) - ; - } - - /** - * - * @return CustomFieldsGroup - */ - private function getCustomFieldsGroup() - { - return (new CustomFieldsGroup()) - ->setEntity('\Dummy') - ->setName(array("fr" => "A cf group")) - ->addCustomField($this->getSimpleCustomFieldText("horses", "Do you like horses ?.")) - ->addCustomField($this->getSimpleCustomFieldText("sure", "Are you sure ?")) - ; - } - + public function testRenderingWidget() { $cfGroup = $this->getCustomFieldsGroup(); - - $text = $this->cfRendering->renderWidget(array( - 'horses' => 'I like horses', - 'sure' => 'Yes !' - ), $cfGroup); - + + $text = $this->cfRendering->renderWidget([ + 'horses' => 'I like horses', + 'sure' => 'Yes !', + ], $cfGroup); + $this->assertContains('Do you like horses', $text); $this->assertContains('I like horses', $text); $this->assertContains('Are you sure', $text); $this->assertContains('Yes', $text); } - + public function testRenderingWidgetDoNotShowEmpty() { $cfGroup = $this->getCustomFieldsGroup(); $cfGroup->addCustomField($this->getSimpleCustomFieldText('empty', 'Do not answer')); - - $text = $this->cfRendering->renderWidget(array( - 'horses' => 'I like horses', - 'sure' => 'Yes !' - ), $cfGroup, 'html', array('show_empty' => false)); - + + $text = $this->cfRendering->renderWidget([ + 'horses' => 'I like horses', + 'sure' => 'Yes !', + ], $cfGroup, 'html', ['show_empty' => false]); + $this->assertContains('Do you like horses', $text); $this->assertContains('I like horses', $text); $this->assertContains('Are you sure', $text); $this->assertContains('Yes', $text); $this->assertNotContains('Do not answer', $text); } + + /** + * @return CustomFieldsGroup + */ + private function getCustomFieldsGroup() + { + return (new CustomFieldsGroup()) + ->setEntity('\Dummy') + ->setName(['fr' => 'A cf group']) + ->addCustomField($this->getSimpleCustomFieldText('horses', 'Do you like horses ?.')) + ->addCustomField($this->getSimpleCustomFieldText('sure', 'Are you sure ?')); + } + + /** + * @param mixed $slug + * @param mixed $name + * + * @return CustomField + */ + private function getSimpleCustomFieldText($slug, $name) + { + return (new CustomField()) + ->setSlug($slug) + ->setName(['fr' => $name]) + ->setType('text') + ->setOrdering(10) + ->setOptions(['maxLength' => 255]) + ->setActive(true); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/Tests/bootstrap.php b/src/Bundle/ChillCustomFieldsBundle/Tests/bootstrap.php index 9211155e5..0eb126c4f 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Tests/bootstrap.php +++ b/src/Bundle/ChillCustomFieldsBundle/Tests/bootstrap.php @@ -1,8 +1,14 @@ addSql("CREATE SEQUENCE CustomField_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE CustomFieldsDefaultGroup_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE CustomFieldsGroup_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE TABLE CustomField (id INT NOT NULL, name JSON NOT NULL, slug VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, active BOOLEAN NOT NULL, ordering DOUBLE PRECISION NOT NULL, options JSON NOT NULL, customFieldGroup_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_40FB5D6DFEC418B ON CustomField (customFieldGroup_id);"); - $this->addSql("CREATE TABLE CustomFieldsDefaultGroup (id INT NOT NULL, entity VARCHAR(255) NOT NULL, customFieldsGroup_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_286DC95DF53B66 ON CustomFieldsDefaultGroup (customFieldsGroup_id);"); - $this->addSql("CREATE UNIQUE INDEX unique_entity ON CustomFieldsDefaultGroup (entity);"); - $this->addSql("CREATE TABLE CustomFieldsGroup (id INT NOT NULL, name JSON NOT NULL, entity VARCHAR(255) NOT NULL, PRIMARY KEY(id));"); - $this->addSql("ALTER TABLE CustomField ADD CONSTRAINT FK_40FB5D6DFEC418B FOREIGN KEY (customFieldGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE CustomFieldsDefaultGroup ADD CONSTRAINT FK_286DC95DF53B66 FOREIGN KEY (customFieldsGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs + } + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE CustomField_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE CustomFieldsDefaultGroup_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE CustomFieldsGroup_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE TABLE CustomField (id INT NOT NULL, name JSON NOT NULL, slug VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, active BOOLEAN NOT NULL, ordering DOUBLE PRECISION NOT NULL, options JSON NOT NULL, customFieldGroup_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_40FB5D6DFEC418B ON CustomField (customFieldGroup_id);'); + $this->addSql('CREATE TABLE CustomFieldsDefaultGroup (id INT NOT NULL, entity VARCHAR(255) NOT NULL, customFieldsGroup_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_286DC95DF53B66 ON CustomFieldsDefaultGroup (customFieldsGroup_id);'); + $this->addSql('CREATE UNIQUE INDEX unique_entity ON CustomFieldsDefaultGroup (entity);'); + $this->addSql('CREATE TABLE CustomFieldsGroup (id INT NOT NULL, name JSON NOT NULL, entity VARCHAR(255) NOT NULL, PRIMARY KEY(id));'); + $this->addSql('ALTER TABLE CustomField ADD CONSTRAINT FK_40FB5D6DFEC418B FOREIGN KEY (customFieldGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE CustomFieldsDefaultGroup ADD CONSTRAINT FK_286DC95DF53B66 FOREIGN KEY (customFieldsGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); } } diff --git a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20150224164531.php b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20150224164531.php index 4034dba80..15c597a77 100644 --- a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20150224164531.php +++ b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20150224164531.php @@ -1,22 +1,29 @@ addSql('ALTER TABLE customfieldsgroup ADD options JSON DEFAULT \'{}\'::json'); - } - public function down(Schema $schema): void { $this->addSql('ALTER TABLE CustomFieldsGroup DROP options'); } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE customfieldsgroup ADD options JSON DEFAULT \'{}\'::json'); + } } diff --git a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210155904.php b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210155904.php index 9bcd83cbc..4e49b5f61 100644 --- a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210155904.php +++ b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210155904.php @@ -1,18 +1,30 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE CustomField DROP required'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -20,16 +32,4 @@ class Version20151210155904 extends AbstractMigration $this->addSql('ALTER TABLE customfield ADD required BOOLEAN DEFAULT FALSE'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE CustomField DROP required'); - - } } diff --git a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210205610.php b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210205610.php index b2f332da4..52ddda8bc 100644 --- a/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210205610.php +++ b/src/Bundle/ChillCustomFieldsBundle/migrations/Version20151210205610.php @@ -1,18 +1,32 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE custom_field_long_choice_options DROP CONSTRAINT cf_long_choice_self_referencing'); + $this->addSql('DROP SEQUENCE custom_field_long_choice_options_id_seq CASCADE'); + $this->addSql('DROP TABLE custom_field_long_choice_options'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -29,19 +43,5 @@ class Version20151210205610 extends AbstractMigration $this->addSql('ALTER TABLE custom_field_long_choice_options ADD CONSTRAINT cf_long_choice_self_referencing ' . 'FOREIGN KEY (parent_id) REFERENCES custom_field_long_choice_options (id) ' . 'NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE custom_field_long_choice_options DROP CONSTRAINT cf_long_choice_self_referencing'); - $this->addSql('DROP SEQUENCE custom_field_long_choice_options_id_seq CASCADE'); - $this->addSql('DROP TABLE custom_field_long_choice_options'); } } diff --git a/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php b/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php index 60649a163..339fb15ee 100644 --- a/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php +++ b/src/Bundle/ChillDocStoreBundle/ChillDocStoreBundle.php @@ -1,5 +1,12 @@ render('ChillDocStoreBundle:Admin:layout.html.twig'); } - + /** * @return \Symfony\Component\HttpFoundation\RedirectResponse */ @@ -26,5 +31,4 @@ class AdminController extends AbstractController { return $this->redirectToRoute('chill_main_admin_central'); } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php index 4d2d3246e..ee11e0164 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentCategoryController.php @@ -1,5 +1,12 @@ getDoctrine()->getManager(); + $documentCategory = $em + ->getRepository('ChillDocStoreBundle:DocumentCategory') + ->findOneBy( + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle] + ); + + if ($this->isCsrfTokenValid('delete' . $bundleId . $idInsideBundle, $request->request->get('_token'))) { + $em->remove($documentCategory); + $em->flush(); + } + + return $this->redirectToRoute('document_category_index'); + } + + /** + * @Route("/{bundleId}/{idInsideBundle}/edit", name="document_category_edit", methods="GET|POST") + * + * @param mixed $bundleId + * @param mixed $idInsideBundle + */ + public function edit(Request $request, $bundleId, $idInsideBundle): Response + { + $em = $this->getDoctrine()->getManager(); + $documentCategory = $em + ->getRepository('ChillDocStoreBundle:DocumentCategory') + ->findOneBy( + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle] + ); + + $form = $this->createForm(DocumentCategoryType::class, $documentCategory); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + return $this->redirectToRoute('document_category_index', [ + 'bundleId' => $documentCategory->getBundleId(), + 'idInsideBundle' => $documentCategory->getIdInsideBundle(), ]); + } + + return $this->render('ChillDocStoreBundle:DocumentCategory:edit.html.twig', [ + 'document_category' => $documentCategory, + 'form' => $form->createView(), + ]); + } + /** * @Route("/", name="document_category_index", methods="GET") */ public function index(): Response { - $em = $this->getDoctrine()->getManager(); - $categories = $em->getRepository("ChillDocStoreBundle:DocumentCategory")->findAll(); + $em = $this->getDoctrine()->getManager(); + $categories = $em->getRepository('ChillDocStoreBundle:DocumentCategory')->findAll(); return $this->render( 'ChillDocStoreBundle:DocumentCategory:index.html.twig', - ['document_categories' => $categories]); + ['document_categories' => $categories] + ); } /** @@ -42,8 +104,9 @@ class DocumentCategoryController extends AbstractController ->setBundleId('Chill\DocStoreBundle\ChillDocStoreBundle'); $documentCategory ->setIdInsideBundle( - $em->getRepository("ChillDocStoreBundle:DocumentCategory") - ->nextIdInsideBundle()); + $em->getRepository('ChillDocStoreBundle:DocumentCategory') + ->nextIdInsideBundle() + ); $documentCategory ->setDocumentClass(PersonDocument::class); @@ -56,10 +119,10 @@ class DocumentCategoryController extends AbstractController $em->flush(); return $this->redirectToRoute('document_category_index'); - } else { - $documentCategory->setBundleId( - 'Chill\DocStoreBundle\ChillDocStoreBundle'); } + $documentCategory->setBundleId( + 'Chill\DocStoreBundle\ChillDocStoreBundle' + ); return $this->render('ChillDocStoreBundle:DocumentCategory:new.html.twig', [ 'document_category' => $documentCategory, @@ -69,64 +132,22 @@ class DocumentCategoryController extends AbstractController /** * @Route("/{bundleId}/{idInsideBundle}", name="document_category_show", methods="GET") + * + * @param mixed $bundleId + * @param mixed $idInsideBundle */ public function show($bundleId, $idInsideBundle): Response { $em = $this->getDoctrine()->getManager(); $documentCategory = $em - ->getRepository("ChillDocStoreBundle:DocumentCategory") + ->getRepository('ChillDocStoreBundle:DocumentCategory') ->findOneBy( - ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); + ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle] + ); return $this->render( 'ChillDocStoreBundle:DocumentCategory:show.html.twig', - ['document_category' => $documentCategory]); - } - - /** - * @Route("/{bundleId}/{idInsideBundle}/edit", name="document_category_edit", methods="GET|POST") - */ - public function edit(Request $request, $bundleId, $idInsideBundle): Response - { - $em = $this->getDoctrine()->getManager(); - $documentCategory = $em - ->getRepository("ChillDocStoreBundle:DocumentCategory") - ->findOneBy( - ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); - - $form = $this->createForm(DocumentCategoryType::class, $documentCategory); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); - - return $this->redirectToRoute('document_category_index', [ - 'bundleId' => $documentCategory->getBundleId(), - 'idInsideBundle' => $documentCategory->getIdInsideBundle(),]); - } - - return $this->render('ChillDocStoreBundle:DocumentCategory:edit.html.twig', [ - 'document_category' => $documentCategory, - 'form' => $form->createView(), - ]); - } - - /** - * @Route("/{bundleId}/{idInsideBundle}", name="document_category_delete", methods="DELETE") - */ - public function delete(Request $request, $bundleId, $idInsideBundle): Response - { - $em = $this->getDoctrine()->getManager(); - $documentCategory = $em - ->getRepository("ChillDocStoreBundle:DocumentCategory") - ->findOneBy( - ['bundleId' => $bundleId, 'idInsideBundle' => $idInsideBundle]); - - if ($this->isCsrfTokenValid('delete'.$bundleId.$idInsideBundle, $request->request->get('_token'))) { - $em->remove($documentCategory); - $em->flush(); - } - - return $this->redirectToRoute('document_category_index'); + ['document_category' => $documentCategory] + ); } } diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php index 57ef81cbb..c0ceed681 100644 --- a/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php +++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentPersonController.php @@ -1,67 +1,147 @@ translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; } - + + /** + * @Route("/{id}", name="person_document_delete", methods="DELETE") + */ + public function delete(Request $request, Person $person, PersonDocument $document): Response + { + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document); + + if ($this->isCsrfTokenValid('delete' . $document->getId(), $request->request->get('_token'))) { + $em = $this->getDoctrine()->getManager(); + $em->remove($document); + $em->flush(); + } + + return $this->redirectToRoute( + 'person_document_index', + ['person' => $person->getId()] + ); + } + + /** + * @Route("/{id}/edit", name="person_document_edit", methods="GET|POST") + */ + public function edit(Request $request, Person $person, PersonDocument $document): Response + { + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_UPDATE', $document); + + $document->setUser($this->getUser()); + $document->setDate(new DateTime('Now')); + + $form = $this->createForm( + PersonDocumentType::class, + $document, + [ + 'center' => $document->getCenter(), + 'role' => new Role('CHILL_PERSON_DOCUMENT_UPDATE'), + ] + ); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->translator->trans('The document is successfully updated')); + + $event = new PrivacyEvent($person, [ + 'element_class' => PersonDocument::class, + 'element_id' => $document->getId(), + 'action' => 'update', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->redirectToRoute( + 'person_document_edit', + ['id' => $document->getId(), 'person' => $person->getId()] + ); + } + + if ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->translator->trans('This form contains errors')); + } + + $event = new PrivacyEvent($person, [ + 'element_class' => PersonDocument::class, + 'element_id' => $document->getId(), + 'action' => 'edit', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render( + 'ChillDocStoreBundle:PersonDocument:edit.html.twig', + [ + 'document' => $document, + 'form' => $form->createView(), + 'person' => $person, + ] + ); + } + /** * @Route("/", name="person_document_index", methods="GET") */ @@ -69,7 +149,7 @@ class DocumentPersonController extends AbstractController { $em = $this->getDoctrine()->getManager(); - if ($person === NULL) { + if (null === $person) { throw $this->createNotFoundException('Person not found'); } @@ -77,28 +157,31 @@ class DocumentPersonController extends AbstractController $reachableScopes = $this->authorizationHelper ->getReachableScopes( - $this->getUser(), new Role(PersonDocumentVoter::SEE), - $person->getCenter()); - - $documents = $em - ->getRepository("ChillDocStoreBundle:PersonDocument") - ->findBy( - array('person' => $person, 'scope' => $reachableScopes), - array('date' => 'DESC') + $this->getUser(), + new Role(PersonDocumentVoter::SEE), + $person->getCenter() ); - $event = new PrivacyEvent($person, array( + $documents = $em + ->getRepository('ChillDocStoreBundle:PersonDocument') + ->findBy( + ['person' => $person, 'scope' => $reachableScopes], + ['date' => 'DESC'] + ); + + $event = new PrivacyEvent($person, [ 'element_class' => PersonDocument::class, - 'action' => 'index' - )); + 'action' => 'index', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - + return $this->render( 'ChillDocStoreBundle:PersonDocument:index.html.twig', [ 'documents' => $documents, - 'person' => $person - ]); + 'person' => $person, + ] + ); } /** @@ -106,7 +189,7 @@ class DocumentPersonController extends AbstractController */ public function new(Request $request, Person $person): Response { - if ($person === NULL) { + if (null === $person) { throw $this->createNotFoundException('person not found'); } @@ -115,28 +198,32 @@ class DocumentPersonController extends AbstractController $document = new PersonDocument(); $document->setUser($this->getUser()); $document->setPerson($person); - $document->setDate(new \DateTime('Now')); + $document->setDate(new DateTime('Now')); - $form = $this->createForm(PersonDocumentType::class, $document, array( + $form = $this->createForm(PersonDocumentType::class, $document, [ 'center' => $document->getCenter(), - 'role' => new Role('CHILL_PERSON_DOCUMENT_CREATE') - )); + 'role' => new Role('CHILL_PERSON_DOCUMENT_CREATE'), + ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $this->denyAccessUnlessGranted( - 'CHILL_PERSON_DOCUMENT_CREATE', $document, - 'creation of this activity not allowed'); + 'CHILL_PERSON_DOCUMENT_CREATE', + $document, + 'creation of this activity not allowed' + ); $em = $this->getDoctrine()->getManager(); $em->persist($document); $em->flush(); - - $this->addFlash('success', $this->translator->trans("The document is successfully registered")); + + $this->addFlash('success', $this->translator->trans('The document is successfully registered')); return $this->redirectToRoute('person_document_index', ['person' => $person->getId()]); - } elseif ($form->isSubmitted() and !$form->isValid()) { - $this->addFlash('error', $this->translator->trans("This form contains errors")); + } + + if ($form->isSubmitted() and !$form->isValid()) { + $this->addFlash('error', $this->translator->trans('This form contains errors')); } return $this->render('ChillDocStoreBundle:PersonDocument:new.html.twig', [ @@ -153,88 +240,17 @@ class DocumentPersonController extends AbstractController { $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_SEE', $document); - - $event = new PrivacyEvent($person, array( + + $event = new PrivacyEvent($person, [ 'element_class' => PersonDocument::class, 'element_id' => $document->getId(), - 'action' => 'show' - )); + 'action' => 'show', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - + return $this->render( 'ChillDocStoreBundle:PersonDocument:show.html.twig', - ['document' => $document, 'person' => $person]); - } - - /** - * @Route("/{id}/edit", name="person_document_edit", methods="GET|POST") - */ - public function edit(Request $request, Person $person, PersonDocument $document): Response - { - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_UPDATE', $document); - - $document->setUser($this->getUser()); - $document->setDate(new \DateTime('Now')); - - $form = $this->createForm( - PersonDocumentType::class, $document, array( - 'center' => $document->getCenter(), - 'role' => new Role('CHILL_PERSON_DOCUMENT_UPDATE'), - )); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); - - $this->addFlash('success', $this->translator->trans("The document is successfully updated")); - - $event = new PrivacyEvent($person, array( - 'element_class' => PersonDocument::class, - 'element_id' => $document->getId(), - 'action' => 'update' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->redirectToRoute( - 'person_document_edit', - ['id' => $document->getId(), 'person' => $person->getId()]); - - } elseif ($form->isSubmitted() and !$form->isValid()) { - $this->addFlash('error', $this->translator->trans("This form contains errors")); - } - - $event = new PrivacyEvent($person, array( - 'element_class' => PersonDocument::class, - 'element_id' => $document->getId(), - 'action' => 'edit' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render( - 'ChillDocStoreBundle:PersonDocument:edit.html.twig', - [ - 'document' => $document, - 'form' => $form->createView(), - 'person' => $person, - ]); - } - - /** - * @Route("/{id}", name="person_document_delete", methods="DELETE") - */ - public function delete(Request $request, Person $person, PersonDocument $document): Response - { - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - $this->denyAccessUnlessGranted('CHILL_PERSON_DOCUMENT_DELETE', $document); - - if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) { - $em = $this->getDoctrine()->getManager(); - $em->remove($document); - $em->flush(); - } - - return $this->redirectToRoute( - 'person_document_index', ['person' => $person->getId()]); + ['document' => $document, 'person' => $person] + ); } } diff --git a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php index 0f4577ffd..8ad9176d5 100644 --- a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php +++ b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentACL.php @@ -1,35 +1,24 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\DocStoreBundle\DataFixtures\ORM; +use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\Entity\RoleScope; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; -use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; /** - * Adding acl for person document - * + * Adding acl for person document. */ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface { @@ -38,13 +27,13 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface return 35000; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); printf("processing permission group %s \n", $permissionsGroup->getName()); - foreach (LoadScopes::$references as $scopeRef){ + + foreach (LoadScopes::$references as $scopeRef) { $scope = $this->getReference($scopeRef); printf("processing scope %s \n", $scope->getName()['en']); //create permission group @@ -52,41 +41,47 @@ class LoadDocumentACL extends AbstractFixture implements OrderedFixtureInterface case 'social': if ($scope->getName()['en'] === 'administrative') { printf("denying power on administrative \n"); + break 2; // we do not want any power on administrative } + break; + case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], ['administrative', 'social'])) { printf("denying power on %s\n", $scope->getName()['en']); + break 2; // we do not want any power on social or administrative - } + } + break; } - - printf("Adding Person report acl to %s " - . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); + + printf( + 'Adding Person report acl to %s ' + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), + $scope->getName()['en'] + ); $roleScopeUpdate = (new RoleScope()) - ->setRole(PersonDocumentVoter::CREATE) - ->setScope($scope); + ->setRole(PersonDocumentVoter::CREATE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreate = (new RoleScope()) - ->setRole(PersonDocumentVoter::UPDATE) - ->setScope($scope); + ->setRole(PersonDocumentVoter::UPDATE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $roleScopeDelete = (new RoleScope()) - ->setRole(PersonDocumentVoter::DELETE) - ->setScope($scope); + ->setRole(PersonDocumentVoter::DELETE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeDelete); $manager->persist($roleScopeUpdate); $manager->persist($roleScopeCreate); $manager->persist($roleScopeDelete); } - } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentCategory.php b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentCategory.php index 2eb6e7181..6b0d30e37 100644 --- a/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentCategory.php +++ b/src/Bundle/ChillDocStoreBundle/DataFixtures/ORM/LoadDocumentCategory.php @@ -1,60 +1,46 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\DocStoreBundle\DataFixtures\ORM; +use Chill\DocStoreBundle\Entity\DocumentCategory; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\DocStoreBundle\Entity\DocumentCategory; -/** - * - * - */ class LoadDocumentCategory extends AbstractFixture implements OrderedFixtureInterface { public function getOrder() { return 35010; } - + public function load(ObjectManager $manager) { $category = (new DocumentCategory('chill-doc-store', 10)) ->setDocumentClass(\Chill\DocStoreBundle\Entity\PersonDocument::class) ->setName([ 'fr' => "Document d'identité", - 'en' => "Identity" - ]) - ; - + 'en' => 'Identity', + ]); + $manager->persist($category); - + $category = (new DocumentCategory('chill-doc-store', 20)) ->setDocumentClass(\Chill\DocStoreBundle\Entity\PersonDocument::class) ->setName([ - 'fr' => "Courrier reçu", - 'en' => "Received email" - ]) - ; - + 'fr' => 'Courrier reçu', + 'en' => 'Received email', + ]); + $manager->persist($category); - + $manager->flush(); } } diff --git a/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.php b/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.php index 63de15f8b..6fd62a7ae 100644 --- a/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.php +++ b/src/Bundle/ChillDocStoreBundle/DependencyInjection/ChillDocStoreExtension.php @@ -1,30 +1,34 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/media.yaml'); $loader->load('services/controller.yaml'); @@ -39,37 +43,37 @@ class ChillDocStoreExtension extends Extension implements PrependExtensionInterf $this->prependAuthorization($container); $this->prependTwig($container); } - + + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + PersonDocumentVoter::UPDATE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::CREATE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::DELETE => [PersonDocumentVoter::SEE_DETAILS], + PersonDocumentVoter::SEE_DETAILS => [PersonDocumentVoter::SEE], + ], + ]); + } + protected function prependRoute(ContainerBuilder $container) { //declare routes for task bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillDocStoreBundle/config/routes.yaml', - '@ChampsLibresAsyncUploaderBundle/config/routes.yaml' - ) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillDocStoreBundle/config/routes.yaml', + '@ChampsLibresAsyncUploaderBundle/config/routes.yaml', + ], + ], + ]); } - - protected function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - PersonDocumentVoter::UPDATE => [PersonDocumentVoter::SEE_DETAILS], - PersonDocumentVoter::CREATE => [PersonDocumentVoter::SEE_DETAILS], - PersonDocumentVoter::DELETE => [PersonDocumentVoter::SEE_DETAILS], - PersonDocumentVoter::SEE_DETAILS => [PersonDocumentVoter::SEE], - ) - )); - } - + protected function prependTwig(ContainerBuilder $container) { - $twigConfig = array( - 'form_themes' => array('@ChillDocStore/Form/fields.html.twig') - ); + $twigConfig = [ + 'form_themes' => ['@ChillDocStore/Form/fields.html.twig'], + ]; $container->prependExtensionConfig('twig', $twigConfig); } } diff --git a/src/Bundle/ChillDocStoreBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillDocStoreBundle/DependencyInjection/Configuration.php index 6c4fa7477..936b41be5 100644 --- a/src/Bundle/ChillDocStoreBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillDocStoreBundle/DependencyInjection/Configuration.php @@ -1,20 +1,24 @@ id; - } - - public function getTitle(): ?string - { - return $this->title; - } - - public function setTitle(string $title): self - { - $this->title = $title; - - return $this; - } - - public function getDescription(): ?string - { - return $this->description; - } - - public function setDescription($description): self - { - $this->description = (string) $description; - - return $this; - } - /** * @return DocumentCategory */ @@ -109,6 +88,46 @@ class Document implements HasScopeInterface return $this->category; } + public function getDate(): ?DateTimeInterface + { + return $this->date; + } + + public function getDescription(): ?string + { + return $this->description; + } + + public function getId() + { + return $this->id; + } + + public function getObject(): ?StoredObject + { + return $this->object; + } + + /** + * Get scope. + * + * @return \Chill\MainBundle\Entity\Scope + */ + public function getScope() + { + return $this->scope; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function getUser() + { + return $this->user; + } + public function setCategory(DocumentCategory $category): self { $this->category = $category; @@ -116,14 +135,25 @@ class Document implements HasScopeInterface return $this; } - /** - * Get scope - * - * @return \Chill\MainBundle\Entity\Scope - */ - public function getScope() + public function setDate(DateTimeInterface $date): self { - return $this->scope; + $this->date = $date; + + return $this; + } + + public function setDescription($description): self + { + $this->description = (string) $description; + + return $this; + } + + public function setObject(?StoredObject $object = null) + { + $this->object = $object; + + return $this; } public function setScope($scope): self @@ -133,9 +163,11 @@ class Document implements HasScopeInterface return $this; } - public function getUser() + public function setTitle(string $title): self { - return $this->user; + $this->title = $title; + + return $this; } public function setUser($user): self @@ -144,28 +176,4 @@ class Document implements HasScopeInterface return $this; } - - public function getDate(): ?\DateTimeInterface - { - return $this->date; - } - - public function setDate(\DateTimeInterface $date): self - { - $this->date = $date; - - return $this; - } - - public function getObject(): ?StoredObject - { - return $this->object; - } - - public function setObject(StoredObject $object = null) - { - $this->object = $object; - - return $this; - } } diff --git a/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php b/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php index a2a8167cc..6cefaaebb 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/DocumentCategory.php @@ -1,9 +1,14 @@ bundleId = $bundleId; $this->idInsideBundle = $idInsideBundle; } - public function getBundleId() // ::class BundleClass (FQDN) + public function getBundleId() // ::class BundleClass (FQDN) { return $this->bundleId; } + public function getDocumentClass() + { + return $this->documentClass; + } + public function getIdInsideBundle() { return $this->idInsideBundle; } - public function getDocumentClass() + public function getName($locale = null) { - return $this->documentClass; + if ($locale) { + if (isset($this->name[$locale])) { + return $this->name[$locale]; + } + + foreach ($this->name as $name) { + if (!empty($name)) { + return $name; + } + } + + return ''; + } + + return $this->name; } public function setDocumentClass($documentClass): self @@ -66,24 +92,6 @@ class DocumentCategory return $this; } - public function getName($locale = null) - { - if ($locale) { - if (isset($this->name[$locale])) { - return $this->name[$locale]; - } else { - foreach ($this->name as $name) { - if (!empty($name)) { - return $name; - } - } - } - return ''; - } else { - return $this->name; - } - } - public function setName($name): self { $this->name = $name; diff --git a/src/Bundle/ChillDocStoreBundle/Entity/PersonDocument.php b/src/Bundle/ChillDocStoreBundle/Entity/PersonDocument.php index b38023ddb..ab026a43b 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/PersonDocument.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/PersonDocument.php @@ -1,29 +1,39 @@ getPerson()->getCenter(); + } + /** - * Get person + * Get person. * * @return \Chill\MainBundle\Entity\Person */ @@ -38,9 +48,4 @@ class PersonDocument extends Document implements HasCenterInterface, HasScopeInt return $this; } - - public function getCenter() - { - return $this->getPerson()->getCenter(); - } } diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php index e145ff1ab..41424f17a 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -1,137 +1,96 @@ - * - * @ORM\Entity() + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\DocStoreBundle\Entity; + +use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface; +use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists; +use DateTime; +use Doctrine\ORM\Mapping as ORM; + +/** + * Represent a document stored in an object store. + * + * @ORM\Entity * @ORM\Table("chill_doc.stored_object") * @AsyncFileExists( - * message="The file is not stored properly" + * message="The file is not stored properly" * ) */ class StoredObject implements AsyncFileInterface { /** - * @ORM\Id() - * @ORM\GeneratedValue() - * @ORM\Column(type="integer") - */ - private $id; - - /** - * @ORM\Column(type="text") - */ - private $filename; - - /** - * @ORM\Column(type="json_array", name="key") - * @var array - */ - private $keyInfos = array(); - - /** - * - * @var int[] - * @ORM\Column(type="json_array", name="iv") - */ - private $iv = array(); - - /** - * - * @var \DateTime + * @var DateTime * @ORM\Column(type="datetime", name="creation_date") */ private $creationDate; - + /** - * - * @var string - * @ORM\Column(type="text", name="type") - */ - private $type = ''; - - /** - * * @var array * @ORM\Column(type="json_array", name="datas") */ private $datas = []; - + + /** + * @ORM\Column(type="text") + */ + private $filename; + + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; + + /** + * @var int[] + * @ORM\Column(type="json_array", name="iv") + */ + private $iv = []; + + /** + * @ORM\Column(type="json_array", name="key") + * + * @var array + */ + private $keyInfos = []; + + /** + * @var string + * @ORM\Column(type="text", name="type") + */ + private $type = ''; + public function __construct() { - $this->creationDate = new \DateTime(); - } - - public function getId() - { - return $this->id; + $this->creationDate = new DateTime(); } - public function getFilename() - { - return $this->filename; - } - - public function getCreationDate(): \DateTime + public function getCreationDate(): DateTime { return $this->creationDate; } - public function getType() - { - return $this->type; - } - public function getDatas() { return $this->datas; } - public function setFilename($filename) + public function getFilename() { - $this->filename = $filename; - - return $this; + return $this->filename; } - public function setCreationDate(\DateTime $creationDate) + public function getId() { - $this->creationDate = $creationDate; - return $this; - } - - public function setType($type) - { - $this->type = $type; - - return $this; - } - - public function setDatas(array $datas) - { - $this->datas = $datas; - - return $this; - } - - public function getObjectName() - { - return $this->getFilename(); - } - - public function getKeyInfos() - { - return $this->keyInfos; + return $this->id; } public function getIv() @@ -139,19 +98,60 @@ class StoredObject implements AsyncFileInterface return $this->iv; } - public function setKeyInfos($keyInfos) + public function getKeyInfos() { - $this->keyInfos = $keyInfos; - + return $this->keyInfos; + } + + public function getObjectName() + { + return $this->getFilename(); + } + + public function getType() + { + return $this->type; + } + + public function setCreationDate(DateTime $creationDate) + { + $this->creationDate = $creationDate; + + return $this; + } + + public function setDatas(array $datas) + { + $this->datas = $datas; + + return $this; + } + + public function setFilename($filename) + { + $this->filename = $filename; + return $this; } public function setIv($iv) { $this->iv = $iv; - + return $this; } + public function setKeyInfos($keyInfos) + { + $this->keyInfos = $keyInfos; + return $this; + } + + public function setType($type) + { + $this->type = $type; + + return $this; + } } diff --git a/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php b/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php index d803405e4..1e2a52592 100644 --- a/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php +++ b/src/Bundle/ChillDocStoreBundle/EntityRepository/DocumentCategoryRepository.php @@ -1,29 +1,18 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\DocStoreBundle\EntityRepository; use Doctrine\ORM\EntityRepository; -use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option; /** - * Get an available idInsideBUndle + * Get an available idInsideBUndle. */ class DocumentCategoryRepository extends EntityRepository { @@ -31,9 +20,10 @@ class DocumentCategoryRepository extends EntityRepository { $array_res = $this->getEntityManager() ->createQuery( - 'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c') + 'SELECT MAX(c.idInsideBundle) + 1 FROM ChillDocStoreBundle:DocumentCategory c' + ) ->getSingleResult(); - return $array_res[1] ?: 0; + return $array_res[1] ?: 0; } } diff --git a/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php b/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php index 9a3f75d8f..aa481160e 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/DocumentCategoryType.php @@ -1,13 +1,20 @@ $value) { - if(substr($key, 0, 5) === 'Chill') { + if (substr($key, 0, 5) === 'Chill') { $this->chillBundlesFlipped[$value] = $key; } } } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('bundleId', ChoiceType::class, array( + ->add('bundleId', ChoiceType::class, [ 'choices' => $this->chillBundlesFlipped, 'disabled' => true, - )) - ->add('idInsideBundle', null, array( + ]) + ->add('idInsideBundle', null, [ 'disabled' => true, - )) - ->add('documentClass', null, array( + ]) + ->add('documentClass', null, [ 'disabled' => true, - )) // cahcerh par default PersonDocument - ->add('name', TranslatableStringFormType::class) - ; + ]) // cahcerh par default PersonDocument + ->add('name', TranslatableStringFormType::class); } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php index 1629410af..fbd87402c 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php @@ -1,76 +1,76 @@ translatableStringHelper = $translatableStringHelper; } - public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', TextType::class) ->add('description', ChillTextareaType::class, [ - 'required' => false + 'required' => false, ]) ->add('object', StoredObjectType::class, [ - 'error_bubbling' => true + 'error_bubbling' => true, ]) ->add('scope', ScopePickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'] + 'role' => $options['role'], ]) ->add('date', ChillDateType::class) - ->add('category', EntityType::class, array( + ->add('category', EntityType::class, [ 'placeholder' => 'Choose a document category', 'class' => 'ChillDocStoreBundle:DocumentCategory', 'query_builder' => function (EntityRepository $er) { @@ -81,9 +81,7 @@ class PersonDocumentType extends AbstractType 'choice_label' => function ($entity = null) { return $entity ? $this->translatableStringHelper->localize($entity->getName()) : ''; }, - )) - ; - + ]); } public function configureOptions(OptionsResolver $resolver) @@ -91,10 +89,9 @@ class PersonDocumentType extends AbstractType $resolver->setDefaults([ 'data_class' => Document::class, ]); - + $resolver->setRequired(['role', 'center']) - ->setAllowedTypes('role', [ \Symfony\Component\Security\Core\Role\Role::class ]) - ->setAllowedTypes('center', [ \Chill\MainBundle\Entity\Center::class ]) - ; + ->setAllowedTypes('role', [\Symfony\Component\Security\Core\Role\Role::class]) + ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class]); } } diff --git a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php index 64cc32e83..eccff8883 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php @@ -1,108 +1,116 @@ em = $em; } - + public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('filename', AsyncUploaderType::class) ->add('type', HiddenType::class) ->add('keyInfos', HiddenType::class) - ->add('iv', HiddenType::class) - ; - + ->add('iv', HiddenType::class); + $builder ->get('keyInfos') ->addModelTransformer(new CallbackTransformer( - [$this, 'transform'], [$this, 'reverseTransform'] - )); + [$this, 'transform'], + [$this, 'reverseTransform'] + )); $builder ->get('iv') ->addModelTransformer(new CallbackTransformer( - [$this, 'transform'], [$this, 'reverseTransform'] - )); - + [$this, 'transform'], + [$this, 'reverseTransform'] + )); + $builder ->addModelTransformer(new CallbackTransformer( - [ $this, 'transformObject'], [$this, 'reverseTransformObject'] - )); + [$this, 'transformObject'], + [$this, 'reverseTransformObject'] + )); } - + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefault('data_class', StoredObject::class); + } + public function getBlockPrefix() { return 'stored_object'; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setDefault('data_class', StoredObject::class) - ; - } - + public function reverseTransform($value) { - if ($value === null) { + if (null === $value) { return null; } - - return \json_decode($value, true); + + return json_decode($value, true); } - + + public function reverseTransformObject($object) + { + if (null === $object) { + return null; + } + + if (null === $object->getFilename()) { + // remove the original object + $this->em->remove($object); + + return null; + } + + return $object; + } + public function transform($object) { - if ($object === null) { + if (null === $object) { return null; } - - return \json_encode($object); + + return json_encode($object); } - + public function transformObject($object = null) { return $object; } - - public function reverseTransformObject($object) - { - if (NULL === $object) { - return null; - } - - if (NULL === $object->getFilename()) { - // remove the original object - $this->em->remove($object); - - return null; - } - - return $object; - } } diff --git a/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php b/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php index 03a8b7038..e83bd7e91 100644 --- a/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillDocStoreBundle/Menu/MenuBuilder.php @@ -1,87 +1,89 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\DocStoreBundle\Menu; + +use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter; +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Knp\Menu\MenuItem; +use LogicException; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Translation\TranslatorInterface; + class MenuBuilder implements LocalMenuBuilderInterface { /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( - TokenStorageInterface $tokenStorage, - AuthorizationHelper $authorizationHelper, + TokenStorageInterface $tokenStorage, + AuthorizationHelper $authorizationHelper, TranslatorInterface $translator - ){ + ) { $this->tokenStorage = $tokenStorage; $this->authorizationHelper = $authorizationHelper; $this->translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { - switch($menuId) { + switch ($menuId) { case 'person': $this->buildMenuPerson($menu, $parameters); + break; + default: - throw new \LogicException("this menuid $menuId is not implemented"); + throw new LogicException("this menuid {$menuId} is not implemented"); } } - + + public static function getMenuIds(): array + { + return ['person']; + } + protected function buildMenuPerson(MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person']; $user = $this->tokenStorage->getToken()->getUser(); - - if ($this->authorizationHelper->userHasAccess($user, - $person->getCenter(), PersonDocumentVoter::SEE)) { - - $menu->addChild($this->translator->trans('Documents'), [ - 'route' => 'person_document_index', - 'routeParameters' => [ - 'person' => $person->getId() - ] - ]) + + if ( + $this->authorizationHelper->userHasAccess( + $user, + $person->getCenter(), + PersonDocumentVoter::SEE + ) + ) { + $menu->addChild($this->translator->trans('Documents'), [ + 'route' => 'person_document_index', + 'routeParameters' => [ + 'person' => $person->getId(), + ], + ]) ->setExtras([ - 'order'=> 350 + 'order' => 350, ]); } - - } - - public static function getMenuIds(): array - { - return [ 'person' ]; } } diff --git a/src/Bundle/ChillDocStoreBundle/Object/ObjectToAsyncFileTransformer.php b/src/Bundle/ChillDocStoreBundle/Object/ObjectToAsyncFileTransformer.php index c5542d667..bdc2ec6f6 100644 --- a/src/Bundle/ChillDocStoreBundle/Object/ObjectToAsyncFileTransformer.php +++ b/src/Bundle/ChillDocStoreBundle/Object/ObjectToAsyncFileTransformer.php @@ -1,33 +1,31 @@ - */ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface { /** - * * @var EntityManagerInterface */ protected $em; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - + public function toAsyncFile($data) { if ($data instanceof StoredObject) { @@ -39,11 +37,9 @@ class ObjectToAsyncFileTransformer implements AsyncFileTransformerInterface { $object = $this->em ->getRepository(StoredObject::class) - ->findByFilename($asyncFile->getObjectName()) - ; - + ->findByFilename($asyncFile->getObjectName()); + return $object ?? (new StoredObject()) - ->setFilename($asyncFile->getObjectName()) - ; + ->setFilename($asyncFile->getObjectName()); } } diff --git a/src/Bundle/ChillDocStoreBundle/Object/PersistenceChecker.php b/src/Bundle/ChillDocStoreBundle/Object/PersistenceChecker.php index 3e0c58189..f5fa006b2 100644 --- a/src/Bundle/ChillDocStoreBundle/Object/PersistenceChecker.php +++ b/src/Bundle/ChillDocStoreBundle/Object/PersistenceChecker.php @@ -1,40 +1,38 @@ - */ class PersistenceChecker implements PersistenceCheckerInterface { /** - * * @var EntityManagerInterface */ protected $em; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - public function isPersisted($object_name): bool { $qb = $this->em->createQueryBuilder(); $qb->select('COUNT(m)') ->from(StoredObject::class, 'm') ->where($qb->expr()->eq('m.filename', ':object_name')) - ->setParameter('object_name', $object_name) - ; - + ->setParameter('object_name', $object_name); + return 1 === $qb->getQuery()->getSingleScalarResult(); } } diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php index 78429b439..76f110bb1 100644 --- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php +++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/PersonDocumentVoter.php @@ -1,57 +1,50 @@ . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\DocStoreBundle\Security\Authorization; +use Chill\DocStoreBundle\Entity\PersonDocument; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Role\Role; use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Role\Role; + +use function in_array; -/** - * - */ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE'; - const SEE = 'CHILL_PERSON_DOCUMENT_SEE'; - const SEE_DETAILS = 'CHILL_PERSON_DOCUMENT_SEE_DETAILS'; - const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE'; - const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE'; + public const CREATE = 'CHILL_PERSON_DOCUMENT_CREATE'; - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + public const DELETE = 'CHILL_PERSON_DOCUMENT_DELETE'; + + public const SEE = 'CHILL_PERSON_DOCUMENT_SEE'; + + public const SEE_DETAILS = 'CHILL_PERSON_DOCUMENT_SEE_DETAILS'; + + public const UPDATE = 'CHILL_PERSON_DOCUMENT_UPDATE'; /** * @var AccessDecisionManagerInterface */ protected $accessDecisionManager; + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; + /** * @var LoggerInterface */ @@ -61,8 +54,7 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera AccessDecisionManagerInterface $accessDecisionManager, AuthorizationHelper $authorizationHelper, LoggerInterface $logger - ) - { + ) { $this->accessDecisionManager = $accessDecisionManager; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; @@ -75,33 +67,51 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera self::SEE, self::SEE_DETAILS, self::UPDATE, - self::DELETE + self::DELETE, ]; } - + + public function getRolesWithHierarchy() + { + return ['PersonDocument' => $this->getRoles()]; + } + + public function getRolesWithoutScope() + { + return []; + } + + protected function isGranted($attribute, $report, $user = null) + { + if (!$user instanceof User) { + return false; + } + + return $this->helper->userHasAccess($user, $report, $attribute); + } + protected function supports($attribute, $subject) { - if (\in_array($attribute, $this->getRoles()) && $subject instanceof PersonDocument) { + if (in_array($attribute, $this->getRoles()) && $subject instanceof PersonDocument) { return true; } - - if ($subject instanceof Person && $attribute === self::CREATE) { + + if ($subject instanceof Person && self::CREATE === $attribute) { return true; } - + return false; } /** - * * @param string $attribute * @param PersonDocument $subject - * @param TokenInterface $token - * @return boolean + * + * @return bool */ protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { - $this->logger->debug(sprintf("Voting from %s class", self::class)); + $this->logger->debug(sprintf('Voting from %s class', self::class)); if (!$token->getUser() instanceof User) { return false; @@ -109,19 +119,18 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera if ($subject instanceof PersonDocument) { return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } elseif ($subject instanceof Person) { - return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } else { - - // subject is null. We check that at least one center is reachable - $centers = $this->authorizationHelper - ->getReachableCenters($token->getUser(), new Role($attribute)); - - return count($centers) > 0; } + if ($subject instanceof Person) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + } + + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper + ->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; + if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { return false; } @@ -131,26 +140,5 @@ class PersonDocumentVoter extends AbstractChillVoter implements ProvideRoleHiera $subject, $attribute ); - - } - - protected function isGranted($attribute, $report, $user = null) - { - if (! $user instanceof User){ - return false; - } - - return $this->helper->userHasAccess($user, $report, $attribute); - } - - public function getRolesWithoutScope() - { - return array(); - } - - - public function getRolesWithHierarchy() - { - return ['PersonDocument' => $this->getRoles() ]; } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php index 8dbc86473..069c6b767 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20180605102533.php @@ -1,15 +1,31 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SCHEMA chill_doc CASCADE'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -28,12 +44,4 @@ final class Version20180605102533 extends AbstractMigration $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53CA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP SCHEMA chill_doc CASCADE'); - - } } diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php index b77debe7b..bdda53e23 100644 --- a/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20180606133338.php @@ -1,15 +1,35 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C232D562B'); + $this->addSql('DROP SEQUENCE chill_doc.stored_object_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_doc.stored_object'); + $this->addSql('ALTER TABLE chill_doc.person_document ADD content TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_doc.person_document DROP object_id'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -24,15 +44,4 @@ final class Version20180606133338 extends AbstractMigration $this->addSql('ALTER TABLE chill_doc.person_document ADD CONSTRAINT FK_41DA53C232D562B FOREIGN KEY (object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_41DA53C232D562B ON chill_doc.person_document (object_id)'); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_doc.person_document DROP CONSTRAINT FK_41DA53C232D562B'); - $this->addSql('DROP SEQUENCE chill_doc.stored_object_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_doc.stored_object'); - $this->addSql('ALTER TABLE chill_doc.person_document ADD content TEXT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_doc.person_document DROP object_id'); - } } diff --git a/src/Bundle/ChillEventBundle/ChillEventBundle.php b/src/Bundle/ChillEventBundle/ChillEventBundle.php index dc040dac6..37dcdbeac 100644 --- a/src/Bundle/ChillEventBundle/ChillEventBundle.php +++ b/src/Bundle/ChillEventBundle/ChillEventBundle.php @@ -1,5 +1,12 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Controller; @@ -24,9 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; /** * Class AdminController - * Controller for the event configuration section (in admin section) - * - * @package Chill\EventBundle\Controller + * Controller for the event configuration section (in admin section). */ class AdminController extends AbstractController { @@ -37,7 +24,7 @@ class AdminController extends AbstractController { return $this->render('ChillEventBundle:Admin:layout.html.twig'); } - + /** * @return \Symfony\Component\HttpFoundation\RedirectResponse */ @@ -45,4 +32,4 @@ class AdminController extends AbstractController { return $this->redirectToRoute('chill_main_admin_central'); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillEventBundle/Controller/EventController.php b/src/Bundle/ChillEventBundle/Controller/EventController.php index 9f4d242d1..06307706b 100644 --- a/src/Bundle/ChillEventBundle/Controller/EventController.php +++ b/src/Bundle/ChillEventBundle/Controller/EventController.php @@ -1,97 +1,75 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Controller; +use Chill\EventBundle\Entity\Event; use Chill\EventBundle\Entity\Participation; +use Chill\EventBundle\Form\EventType; use Chill\EventBundle\Form\Type\PickEventType; +use Chill\EventBundle\Security\Authorization\EventVoter; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Pagination\PaginatorFactory; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Form\Type\PickPersonType; +use Chill\PersonBundle\Privacy\PrivacyEvent; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Csv; use PhpOffice\PhpSpreadsheet\Writer\Ods; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\HttpFoundation\StreamedResponse; -use Chill\EventBundle\Security\Authorization\EventVoter; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Privacy\PrivacyEvent; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Request; -use Chill\PersonBundle\Form\Type\PickPersonType; -use Chill\EventBundle\Entity\Event; -use Chill\EventBundle\Form\EventType; -use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Form\Extension\Core\Type\FormType; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; -use Chill\MainBundle\Entity\Center; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\Translation\TranslatorInterface; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; - +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Translation\TranslatorInterface; /** - * Class EventController - * - * @package Chill\EventBundle\Controller + * Class EventController. */ class EventController extends AbstractController { - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - /** * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + /** * @var FormFactoryInterface */ protected $formFactoryInterface; - - /** - * @var TranslatorInterface - */ - protected $translator; - + /** * @var PaginatorFactory */ protected $paginator; - + + /** + * @var TranslatorInterface + */ + protected $translator; + /** * EventController constructor. - * - * @param EventDispatcherInterface $eventDispatcher - * @param AuthorizationHelper $authorizationHelper - * @param FormFactoryInterface $formFactoryInterface - * @param TranslatorInterface $translator - * @param PaginatorFactory $paginator */ public function __construct( EventDispatcherInterface $eventDispatcher, @@ -99,200 +77,70 @@ class EventController extends AbstractController FormFactoryInterface $formFactoryInterface, TranslatorInterface $translator, PaginatorFactory $paginator - ) - { + ) { $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; $this->formFactoryInterface = $formFactoryInterface; $this->translator = $translator; $this->paginator = $paginator; } - - - public function mostRecentIndexAction() - { - return $this->redirectToRoute('chill_main_search', array( - 'q' => '@event' - )); - } - /** - * First step of new Event form - */ - public function newPickCenterAction() - { - $role = new Role('CHILL_EVENT_CREATE'); - - /** - * @var Center $centers - */ - $centers = $this->authorizationHelper->getReachableCenters($this->getUser(), $role); - - if (count($centers) === 1) - { - return $this->redirectToRoute('chill_event__event_new', array( - 'center_id' => $centers[0]->getId() - )); - } - - $form = $this->formFactoryInterface - ->createNamedBuilder(null, FormType::class, null, array( - 'csrf_protection' => false - )) - ->setMethod('GET') - ->setAction( - $this->generateUrl('chill_event__event_new')) - ->add('center_id', EntityType::class, array( - 'class' => Center::class, - 'choices' => $centers, - 'placeholder' => '', - 'label' => 'To which centre should the event be associated ?' - )) - ->add('submit', SubmitType::class, array( - 'label' => 'Next step' - )) - ->getForm(); - - return $this->render('ChillEventBundle:Event:newPickCenter.html.twig', array( - 'form' => $form->createView() - )); - - } - - /** - * Creates a form to create a Event entity. + * @param $event_id * - * @param Event $entity The entity - * @return \Symfony\Component\Form\FormInterface + * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response */ - private function createCreateForm(Event $entity) + public function deleteAction($event_id, Request $request) { - $form = $this->createForm(EventType::class, $entity, array( - 'method' => 'POST', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_EVENT_CREATE') - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new Event entity. - * @param Center $center - * @param Request $request - * @return \Symfony\Component\HttpFoundation\Response - */ - public function newAction(Center $center = null, Request $request) - { - if ($center === null) - { - $center_id = $request->query->get('center_id'); - $center = $this->getDoctrine()->getRepository(Center::class)->find($center_id); - } - - $entity = new Event(); - $entity->setCenter($center); - - $form = $this->createCreateForm($entity); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) - { - $em = $this->getDoctrine()->getManager(); - $em->persist($entity); - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans('The event was created')); - - return $this->redirect($this->generateUrl('chill_event__event_show', array('event_id' => $entity->getId()))); - } + $em = $this->getDoctrine()->getManager(); + $event = $em->getRepository('ChillEventBundle:Event')->findOneBy([ + 'id' => $event_id, + ]); - return $this->render('ChillEventBundle:Event:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Event entity. - * - * @ParamConverter("event", options={"id" = "event_id"}) - * @param Event $event - * @param Request $request - * @return \Symfony\Component\HttpFoundation\Response - * @throws \PhpOffice\PhpSpreadsheet\Exception - */ - public function showAction(Event $event, Request $request) - { if (!$event) { - throw $this->createNotFoundException('Unable to find Event entity.'); + throw $this->createNotFoundException('Unable to find this event.'); } - $this->denyAccessUnlessGranted('CHILL_EVENT_SEE_DETAILS', $event, - "You are not allowed to see details on this event"); - - $addParticipationByPersonForm = $this->createAddParticipationByPersonForm($event); - - $exportParticipationsList = $this->exportParticipationsList($event, $request); - - if ($exportParticipationsList['response']) { - return $exportParticipationsList['response']; + /** @var array $participations */ + $participations = $event->getParticipations(); + + $form = $this->createDeleteForm($event_id); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + foreach ($participations as $participation) { + $em->remove($participation); + } + + $em->remove($event); + $em->flush(); + + $this->addFlash( + 'success', + $this->get('translator') + ->trans('The event has been sucessfully removed') + ); + + return $this->redirectToRoute('chill_main_search', [ + 'name' => 'event_regular', + 'q' => '@event', + ]); + } } - - return $this->render('ChillEventBundle:Event:show.html.twig', array( - 'event' => $event, - 'form_add_participation_by_person' => $addParticipationByPersonForm->createView(), - 'form_export' => $exportParticipationsList['form']->createView() - )); - } - - /** - * create a form to add a participation with a person - * - * @param Event $event - * @return \Symfony\Component\Form\FormInterface - */ - protected function createAddParticipationByPersonForm(Event $event) - { - /* @var $builder \Symfony\Component\Form\FormBuilderInterface */ - $builder = $this - ->get('form.factory') - ->createNamedBuilder( - null, - FormType::class, - null, - array( - 'method' => 'GET', - 'action' => $this->generateUrl('chill_event_participation_new'), - 'csrf_protection' => false - )) - ; - - $builder->add('person_id', PickPersonType::class, array( - 'role' => new Role('CHILL_EVENT_CREATE'), - 'centers' => $event->getCenter() - )); - - $builder->add('event_id', HiddenType::class, array( - 'data' => $event->getId() - )); - - $builder->add('submit', SubmitType::class, - array( - 'label' => 'Add a participation' - )); - - return $builder->getForm(); + + return $this->render('ChillEventBundle:Event:confirm_delete.html.twig', [ + 'event_id' => $event->getId(), + 'delete_form' => $form->createView(), + ]); } /** * Displays a form to edit an existing Event entity. * * @param $event_id + * * @return \Symfony\Component\HttpFoundation\Response */ public function editAction($event_id) @@ -307,39 +155,193 @@ class EventController extends AbstractController $editForm = $this->createEditForm($entity); - return $this->render('ChillEventBundle:Event:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillEventBundle:Event:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a Event entity. + * List events subscriptions for a person. * - * @param Event $entity - * @return \Symfony\Component\Form\FormInterface + * @param $person_id + * + * @throws \Doctrine\ORM\NonUniqueResultException + * + * @return \Symfony\Component\HttpFoundation\Response */ - private function createEditForm(Event $entity) + public function listByPersonAction($person_id) { - $form = $this->createForm(EventType::class, $entity, array( - 'action' => $this->generateUrl('chill_event__event_update', array('event_id' => $entity->getId())), - 'method' => 'PUT', - 'center' => $entity->getCenter(), - 'role' => new Role('CHILL_EVENT_CREATE') - )); + $em = $this->getDoctrine()->getManager(); - $form->remove('center'); + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + if (null === $person) { + throw $this->createNotFoundException('Person not found'); + } - return $form; + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $reachablesCircles = $this->authorizationHelper->getReachableCircles( + $this->getUser(), + new Role(EventVoter::SEE), + $person->getCenter() + ); + + $total = $em->getRepository('ChillEventBundle:Participation')->countByPerson($person_id); + + $paginator = $this->paginator->create($total); + + $participations = $em->getRepository('ChillEventBundle:Participation')->findByPersonInCircle( + $person_id, + $reachablesCircles, + $paginator->getCurrentPage()->getFirstItemNumber(), + $paginator->getItemsPerPage() + ); + + $privacyEvent = new PrivacyEvent($person, [ + 'element_class' => Participation::class, + 'action' => 'list', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $privacyEvent); + + $addEventParticipationByPersonForm = $this->createAddEventParticipationByPersonForm($person); + + return $this->render('ChillEventBundle:Event:listByPerson.html.twig', [ + 'participations' => $participations, + 'person' => $person, + 'paginator' => $paginator, + 'form_add_event_participation_by_person' => $addEventParticipationByPersonForm->createView(), + ]); } - + + public function mostRecentIndexAction() + { + return $this->redirectToRoute('chill_main_search', [ + 'q' => '@event', + ]); + } + + /** + * Displays a form to create a new Event entity. + * + * @param Center $center + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function newAction(?Center $center = null, Request $request) + { + if (null === $center) { + $center_id = $request->query->get('center_id'); + $center = $this->getDoctrine()->getRepository(Center::class)->find($center_id); + } + + $entity = new Event(); + $entity->setCenter($center); + + $form = $this->createCreateForm($entity); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($entity); + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The event was created')); + + return $this->redirect($this->generateUrl('chill_event__event_show', ['event_id' => $entity->getId()])); + } + + return $this->render('ChillEventBundle:Event:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * First step of new Event form. + */ + public function newPickCenterAction() + { + $role = new Role('CHILL_EVENT_CREATE'); + + /** + * @var Center $centers + */ + $centers = $this->authorizationHelper->getReachableCenters($this->getUser(), $role); + + if (count($centers) === 1) { + return $this->redirectToRoute('chill_event__event_new', [ + 'center_id' => $centers[0]->getId(), + ]); + } + + $form = $this->formFactoryInterface + ->createNamedBuilder(null, FormType::class, null, [ + 'csrf_protection' => false, + ]) + ->setMethod('GET') + ->setAction( + $this->generateUrl('chill_event__event_new') + ) + ->add('center_id', EntityType::class, [ + 'class' => Center::class, + 'choices' => $centers, + 'placeholder' => '', + 'label' => 'To which centre should the event be associated ?', + ]) + ->add('submit', SubmitType::class, [ + 'label' => 'Next step', + ]) + ->getForm(); + + return $this->render('ChillEventBundle:Event:newPickCenter.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Event entity. + * + * @ParamConverter("event", options={"id": "event_id"}) + * + * @throws \PhpOffice\PhpSpreadsheet\Exception + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function showAction(Event $event, Request $request) + { + if (!$event) { + throw $this->createNotFoundException('Unable to find Event entity.'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_EVENT_SEE_DETAILS', + $event, + 'You are not allowed to see details on this event' + ); + + $addParticipationByPersonForm = $this->createAddParticipationByPersonForm($event); + + $exportParticipationsList = $this->exportParticipationsList($event, $request); + + if ($exportParticipationsList['response']) { + return $exportParticipationsList['response']; + } + + return $this->render('ChillEventBundle:Event:show.html.twig', [ + 'event' => $event, + 'form_add_participation_by_person' => $addParticipationByPersonForm->createView(), + 'form_export' => $exportParticipationsList['form']->createView(), + ]); + } + /** * Edits an existing Event entity. * - * @param Request $request * @param $event_id + * * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response */ public function updateAction(Request $request, $event_id) @@ -357,76 +359,22 @@ class EventController extends AbstractController if ($editForm->isValid()) { $em->flush(); - + $this->addFlash('success', $this->get('translator') - ->trans('The event was updated')); + ->trans('The event was updated')); - return $this->redirect($this->generateUrl('chill_event__event_edit', array('event_id' => $event_id))); + return $this->redirect($this->generateUrl('chill_event__event_edit', ['event_id' => $event_id])); } - return $this->render('ChillEventBundle:Event:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - )); + return $this->render('ChillEventBundle:Event:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + ]); } - - /** - * List events subscriptions for a person - * - * @param $person_id - * @return \Symfony\Component\HttpFoundation\Response - * @throws \Doctrine\ORM\NonUniqueResultException - */ - public function listByPersonAction($person_id) - { - - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - if ($person === NULL) { - throw $this->createNotFoundException('Person not found'); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $reachablesCircles = $this->authorizationHelper->getReachableCircles( - $this->getUser(), - new Role(EventVoter::SEE), - $person->getCenter() - ); - - $total = $em->getRepository('ChillEventBundle:Participation')->countByPerson($person_id); - - $paginator = $this->paginator->create($total); - $participations = $em->getRepository('ChillEventBundle:Participation')->findByPersonInCircle( - $person_id, - $reachablesCircles, - $paginator->getCurrentPage()->getFirstItemNumber(), - $paginator->getItemsPerPage() - ); - - $privacyEvent = new PrivacyEvent($person, array( - 'element_class' => Participation::class, - 'action' => 'list' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $privacyEvent); - - $addEventParticipationByPersonForm = $this->createAddEventParticipationByPersonForm($person); - - return $this->render('ChillEventBundle:Event:listByPerson.html.twig', array( - 'participations' => $participations, - 'person' => $person, - 'paginator' => $paginator, - 'form_add_event_participation_by_person' => $addEventParticipationByPersonForm->createView() - )); - } - /** - * create a form to add a participation with an event + * create a form to add a participation with an event. * - * @param Person $person * @return \Symfony\Component\Form\FormInterface */ protected function createAddEventParticipationByPersonForm(Person $person) @@ -438,90 +386,80 @@ class EventController extends AbstractController null, FormType::class, null, - array( + [ 'method' => 'GET', 'action' => $this->generateUrl('chill_event_participation_new'), - 'csrf_protection' => false - )) - ; - - $builder->add('event_id', PickEventType::class, array( + 'csrf_protection' => false, + ] + ); + + $builder->add('event_id', PickEventType::class, [ 'role' => new Role('CHILL_EVENT_CREATE'), - 'centers' => $person->getCenter() - )); - - $builder->add('person_id', HiddenType::class, array( - 'data' => $person->getId() - )); - - $builder->add('return_path', HiddenType::class, array( - 'data' => $this->generateUrl('chill_event__list_by_person', array( - 'person_id' => $person->getId() - )) - )); - - - $builder->add('submit', SubmitType::class, - array( - 'label' => 'Subscribe an event' - )); - + 'centers' => $person->getCenter(), + ]); + + $builder->add('person_id', HiddenType::class, [ + 'data' => $person->getId(), + ]); + + $builder->add('return_path', HiddenType::class, [ + 'data' => $this->generateUrl('chill_event__list_by_person', [ + 'person_id' => $person->getId(), + ]), + ]); + + $builder->add( + 'submit', + SubmitType::class, + [ + 'label' => 'Subscribe an event', + ] + ); + return $builder->getForm(); } - - + /** - * @param Event $event - * @param Request $request - * @return array - * @throws \PhpOffice\PhpSpreadsheet\Exception + * create a form to add a participation with a person. + * + * @return \Symfony\Component\Form\FormInterface */ - protected function exportParticipationsList(Event $event, Request $request) + protected function createAddParticipationByPersonForm(Event $event) { - $form = $this->createExportByFormatForm(); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) - { - $data = $form->getData(); - $format = $data['format']; - $filename = 'export_event'. $event->getId() .'_participations.' .$format; - - $spreadsheet = $this->createExportSpreadsheet($event); - - switch ($format) { - case 'ods': - $contentType = 'application/vnd.oasis.opendocument.spreadsheet'; - $writer = new Ods($spreadsheet); - break; - case 'xlsx': - $contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; - $writer = new Xlsx($spreadsheet); - break; - case 'csv': - $contentType = 'text/csv'; - $writer = new Csv($spreadsheet); - break; - default: - return [ 'form' => $form, 'response' => null ]; - } - - $response = new StreamedResponse(); - $response->headers->set('Content-Type', $contentType); - $response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"'); - $response->setPrivate(); - $response->headers->addCacheControlDirective('no-cache', true); - $response->headers->addCacheControlDirective('must-revalidate', true); - $response->setCallback(function() use ($writer) { - $writer->save('php://output'); - }); - - return [ 'form' => $form, 'response' => $response ]; - } - - return [ 'form' => $form, 'response' => null ]; + /* @var $builder \Symfony\Component\Form\FormBuilderInterface */ + $builder = $this + ->get('form.factory') + ->createNamedBuilder( + null, + FormType::class, + null, + [ + 'method' => 'GET', + 'action' => $this->generateUrl('chill_event_participation_new'), + 'csrf_protection' => false, + ] + ); + + $builder->add('person_id', PickPersonType::class, [ + 'role' => new Role('CHILL_EVENT_CREATE'), + 'centers' => $event->getCenter(), + ]); + + $builder->add('event_id', HiddenType::class, [ + 'data' => $event->getId(), + ]); + + $builder->add( + 'submit', + SubmitType::class, + [ + 'label' => 'Add a participation', + ] + ); + + return $builder->getForm(); } - + /** * @return \Symfony\Component\Form\FormInterface */ @@ -532,30 +470,30 @@ class EventController extends AbstractController 'choices' => [ 'xlsx' => 'xlsx', 'ods' => 'ods', - 'csv' => 'csv' + 'csv' => 'csv', ], 'label' => false, - 'placeholder' => 'Select a format' + 'placeholder' => 'Select a format', ]) ->add('submit', SubmitType::class, [ - 'label' => 'Export' + 'label' => 'Export', ]); - + return $builder->getForm(); } - + /** - * @param Event $event - * @return Spreadsheet * @throws \PhpOffice\PhpSpreadsheet\Exception + * + * @return Spreadsheet */ protected function createExportSpreadsheet(Event $event) { $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - + $trans = $this->translator->getLocale(); - + $headerValues = [ 'A1' => 'Event', 'B1' => $event->getId(), @@ -570,20 +508,22 @@ class EventController extends AbstractController 'A6' => 'Moderator', 'B6' => $event->getModerator() ? $event->getModerator()->getUsernameCanonical() : null, ]; + foreach ($headerValues as $k => $value) { $sheet->setCellValue($k, $value); } - - $columnNames = [ 'id', 'firstname', 'lastname', 'role', 'status', 'email', 'phone', 'mobile' ]; + + $columnNames = ['id', 'firstname', 'lastname', 'role', 'status', 'email', 'phone', 'mobile']; $columnLetter = 'A'; + foreach ($columnNames as $columnName) { - $sheet->setCellValue($columnLetter.'8', $columnName); - $columnLetter++; + $sheet->setCellValue($columnLetter . '8', $columnName); + ++$columnLetter; } - + $columnValues = []; - foreach ($event->getParticipations() as $participation) - { + + foreach ($event->getParticipations() as $participation) { /** @var Participation $participation */ $columnValues[] = [ $participation->getPerson()->getId(), @@ -596,83 +536,132 @@ class EventController extends AbstractController $participation->getPerson()->getMobileNumber(), ]; } - + $i = 9; + foreach ($columnValues as $columnValue) { $columnLetter = 'A'; + foreach ($columnValue as $value) { - $sheet->setCellValue($columnLetter.$i, $value); - $columnLetter++; + $sheet->setCellValue($columnLetter . $i, $value); + ++$columnLetter; } - $i++; + ++$i; } - + return $spreadsheet; } - + /** - * @param $event_id - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response + * @throws \PhpOffice\PhpSpreadsheet\Exception + * + * @return array */ - public function deleteAction($event_id, Request $request) + protected function exportParticipationsList(Event $event, Request $request) { - $em = $this->getDoctrine()->getManager(); - $event = $em->getRepository('ChillEventBundle:Event')->findOneBy([ - 'id' => $event_id - ]); - - if (! $event) { - throw $this->createNotFoundException('Unable to find this event.'); - } - - /** @var array $participations */ - $participations = $event->getParticipations(); - - $form = $this->createDeleteForm($event_id); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - - foreach ($participations as $participation) { - $em->remove($participation); - } - - $em->remove($event); - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans("The event has been sucessfully removed") - ); - - return $this->redirectToRoute('chill_main_search', [ - 'name' => 'event_regular', - 'q' => '@event' - ]); + $form = $this->createExportByFormatForm(); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $data = $form->getData(); + $format = $data['format']; + $filename = 'export_event' . $event->getId() . '_participations.' . $format; + + $spreadsheet = $this->createExportSpreadsheet($event); + + switch ($format) { + case 'ods': + $contentType = 'application/vnd.oasis.opendocument.spreadsheet'; + $writer = new Ods($spreadsheet); + + break; + + case 'xlsx': + $contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; + $writer = new Xlsx($spreadsheet); + + break; + + case 'csv': + $contentType = 'text/csv'; + $writer = new Csv($spreadsheet); + + break; + + default: + return ['form' => $form, 'response' => null]; } + + $response = new StreamedResponse(); + $response->headers->set('Content-Type', $contentType); + $response->headers->set('Content-Disposition', 'attachment;filename="' . $filename . '"'); + $response->setPrivate(); + $response->headers->addCacheControlDirective('no-cache', true); + $response->headers->addCacheControlDirective('must-revalidate', true); + $response->setCallback(function () use ($writer) { + $writer->save('php://output'); + }); + + return ['form' => $form, 'response' => $response]; } - return $this->render('ChillEventBundle:Event:confirm_delete.html.twig', [ - 'event_id' => $event->getId(), - 'delete_form' => $form->createView() - ]); + + return ['form' => $form, 'response' => null]; } - + + /** + * Creates a form to create a Event entity. + * + * @param Event $entity The entity + * + * @return \Symfony\Component\Form\FormInterface + */ + private function createCreateForm(Event $entity) + { + $form = $this->createForm(EventType::class, $entity, [ + 'method' => 'POST', + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_EVENT_CREATE'), + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + /** * @param $event_id + * * @return \Symfony\Component\Form\FormInterface */ private function createDeleteForm($event_id) { return $this->createFormBuilder() ->setAction($this->generateUrl('chill_event__event_delete', [ - 'event_id' => $event_id + 'event_id' => $event_id, ])) ->setMethod('DELETE') ->add('submit', SubmitType::class, ['label' => 'Delete']) - ->getForm() - ; + ->getForm(); + } + + /** + * Creates a form to edit a Event entity. + * + * @return \Symfony\Component\Form\FormInterface + */ + private function createEditForm(Event $entity) + { + $form = $this->createForm(EventType::class, $entity, [ + 'action' => $this->generateUrl('chill_event__event_update', ['event_id' => $entity->getId()]), + 'method' => 'PUT', + 'center' => $entity->getCenter(), + 'role' => new Role('CHILL_EVENT_CREATE'), + ]); + + $form->remove('center'); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } - } diff --git a/src/Bundle/ChillEventBundle/Controller/EventTypeController.php b/src/Bundle/ChillEventBundle/Controller/EventTypeController.php index e151f04cb..f9478e194 100644 --- a/src/Bundle/ChillEventBundle/Controller/EventTypeController.php +++ b/src/Bundle/ChillEventBundle/Controller/EventTypeController.php @@ -1,39 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillEventBundle:EventType')->findAll(); - - return $this->render('ChillEventBundle:EventType:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new EventType entity. - * */ public function createAction(Request $request) { @@ -46,149 +34,22 @@ class EventTypeController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_eventtype_admin', - array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl( + 'chill_eventtype_admin', + ['id' => $entity->getId()] + )); } - return $this->render('ChillEventBundle:EventType:new.html.twig', array( + return $this->render('ChillEventBundle:EventType:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); + 'form' => $form->createView(), + ]); } - /** - * Creates a form to create a EventType entity. - * - * @param EventType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(EventType $entity) - { - $form = $this->createForm(EventTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_eventtype_admin_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new EventType entity. - * - */ - public function newAction() - { - $entity = new EventType(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillEventBundle:EventType:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a EventType entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find EventType entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:EventType:show.html.twig', array( - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Displays a form to edit an existing EventType entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find EventType entity.'); - } - - $editForm = $this->createEditForm($entity); - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:EventType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Creates a form to edit a EventType entity. - * - * @param EventType $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(EventType $entity) - { - $form = $this->createForm(EventTypeType::class, $entity, array( - 'action' => $this->generateUrl('chill_eventtype_admin_update', - array('id' => $entity->getId())), - 'method' => 'PUT', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - /** - * Edits an existing EventType entity. - * - */ - public function updateAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find EventType entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - $em->flush(); - - return $this->redirect($this->generateUrl('chill_eventtype_admin', - array('id' => $id))); - } - - return $this->render('ChillEventBundle:EventType:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } /** * Deletes a EventType entity. * + * @param mixed $id */ public function deleteAction(Request $request, $id) { @@ -210,6 +71,136 @@ class EventTypeController extends AbstractController return $this->redirect($this->generateUrl('chill_eventtype_admin')); } + /** + * Displays a form to edit an existing EventType entity. + * + * @param mixed $id + */ + public function editAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find EventType entity.'); + } + + $editForm = $this->createEditForm($entity); + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:EventType:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Lists all EventType entities. + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + + $entities = $em->getRepository('ChillEventBundle:EventType')->findAll(); + + return $this->render('ChillEventBundle:EventType:index.html.twig', [ + 'entities' => $entities, + ]); + } + + /** + * Displays a form to create a new EventType entity. + */ + public function newAction() + { + $entity = new EventType(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillEventBundle:EventType:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a EventType entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find EventType entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:EventType:show.html.twig', [ + 'entity' => $entity, + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Edits an existing EventType entity. + * + * @param mixed $id + */ + public function updateAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:EventType')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find EventType entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + $editForm = $this->createEditForm($entity); + $editForm->handleRequest($request); + + if ($editForm->isValid()) { + $em->flush(); + + return $this->redirect($this->generateUrl( + 'chill_eventtype_admin', + ['id' => $id] + )); + } + + return $this->render('ChillEventBundle:EventType:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Creates a form to create a EventType entity. + * + * @param EventType $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(EventType $entity) + { + $form = $this->createForm(EventTypeType::class, $entity, [ + 'action' => $this->generateUrl('chill_eventtype_admin_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + /** * Creates a form to delete a EventType entity by id. * @@ -220,11 +211,34 @@ class EventTypeController extends AbstractController private function createDeleteForm($id) { return $this->createFormBuilder() - ->setAction($this->generateUrl('chill_eventtype_admin_delete', - array('id' => $id))) + ->setAction($this->generateUrl( + 'chill_eventtype_admin_delete', + ['id' => $id] + )) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + /** + * Creates a form to edit a EventType entity. + * + * @param EventType $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(EventType $entity) + { + $form = $this->createForm(EventTypeType::class, $entity, [ + 'action' => $this->generateUrl( + 'chill_eventtype_admin_update', + ['id' => $entity->getId()] + ), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillEventBundle/Controller/ParticipationController.php b/src/Bundle/ChillEventBundle/Controller/ParticipationController.php index 4242eb784..9d512ff28 100644 --- a/src/Bundle/ChillEventBundle/Controller/ParticipationController.php +++ b/src/Bundle/ChillEventBundle/Controller/ParticipationController.php @@ -1,766 +1,784 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Controller; use ArrayIterator; use Chill\EventBundle\Entity\Event; -use Psr\Log\LoggerInterface; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Chill\EventBundle\Entity\Participation; use Chill\EventBundle\Form\ParticipationType; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Chill\EventBundle\Security\Authorization\ParticipationVoter; +use LogicException; +use Psr\Log\LoggerInterface; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\CollectionType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** - * Class ParticipationController - * - * @package Chill\EventBundle\Controller - * @author Julien Fastré + * Class ParticipationController. */ class ParticipationController extends AbstractController { - /** * @var \Psr\Log\LoggerInterface */ private $logger; - + /** * ParticipationController constructor. - * - * @param LoggerInterface $logger */ public function __construct(LoggerInterface $logger) { $this->logger = $logger; } - - /** - * Show a form to add a participation - * - * This function parse the person_id / persons_ids query argument - * and decide if it should process a single or multiple participation. Depending - * on this, the appropriate layout and form. - * - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function newAction(Request $request) - { - - // test the request is correct - try { - $this->testRequest($request); - } catch (\RuntimeException $ex) { - $this->logger->warning($ex->getMessage()); - - return (new Response()) - ->setStatusCode(Response::HTTP_BAD_REQUEST) - ->setContent($ex->getMessage()); - } - - // forward to other action - $single = $request->query->has('person_id'); - $multiple = $request->query->has('persons_ids'); - - if ($single === true) { - return $this->newSingle($request); - } - - if ($multiple === true) { - - return $this->newMultiple($request); - } - - // at this point, we miss the required fields. Throw an error - return (new Response()) - ->setStatusCode(Response::HTTP_BAD_REQUEST) - ->setContent("You must provide either 'person_id' or " - . "'persons_ids' argument in query"); - } - - /** - * - * Test that the query parameters are valid : - * - * - an `event_id` is existing ; - * - `person_id` and `persons_ids` are **not** both present ; - * - `persons_id` is correct (contains only numbers and a ','. - * - * @param Request $request - * @throws \RuntimeException if an error is detected - */ - protected function testRequest(Request $request) - { - $single = $request->query->has('person_id'); - $multiple = $request->query->has('persons_ids'); - - if ($single === true AND $multiple === true) { - // we are not allowed to have both person_id and persons_ids - throw new \RuntimeException("You are not allow to provide both 'person_id' and " - . "'persons_ids' simulaneously"); - } - - if ($multiple === true) { - $persons_ids = $request->query->get('persons_ids'); - - if (!preg_match('/^([0-9]{1,},{0,1}){1,}[0-9]{0,}$/', $persons_ids)) { - throw new \RuntimeException("The persons_ids value should " - . "contains int separated by ','"); - } - } - - // check for event_id - this could be removed later - if ($request->query->has('event_id') === FALSE) { - throw new \RuntimeException("You must provide an event_id"); - } - - } - - /** - * Show a form with single participation. - * - * @param Request $request - * @return Response - */ - protected function newSingle(Request $request) - { - - $returnPath = $request->query->get('return_path') ? - $request->query->get('return_path') : null; - - $participation = $this->handleRequest($request, new Participation(), false); - - $this->denyAccessUnlessGranted(ParticipationVoter::CREATE, - $participation, 'The user is not allowed to create this participation'); - - $form = $this->createCreateForm($participation, $returnPath); - - return $this->render('ChillEventBundle:Participation:new.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation, - 'ignored_participations' => array() // this is required, see self::newMultiple - )); - } - - /** - * Show a form with multiple participation. - * - * If a person is already participating on the event (if a participation with - * the same person is associated with the event), the participation is ignored. - * - * If all but one participation is ignored, the page show the same response - * than the newSingle function. - * - * If all participations must be ignored, an error is shown and the method redirects - * to the event 'show' view with an appropriate flash message. - * - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - protected function newMultiple(Request $request) - { - $participations = $this->handleRequest($request, new Participation(), true); - - - foreach ($participations as $i => $participation) { - // check for authorization - $this->denyAccessUnlessGranted(ParticipationVoter::CREATE, - $participation, 'The user is not allowed to create this participation'); - - // create a collection of person's id participating to the event - /* @var $peopleParticipating \Doctrine\Common\Collections\ArrayCollection */ - $peopleParticipating = isset($peopleParticipating) ? $peopleParticipating : - $participation->getEvent()->getParticipations()->map( - function(Participation $p) { return $p->getPerson()->getId(); } - ); - // check that the user is not already in the event - if ($peopleParticipating->contains($participation->getPerson()->getId())) { - $ignoredParticipations[] = $participation - ->getEvent()->getParticipations()->filter( - function (Participation $p) use ($participation) { - return $p->getPerson()->getId() === $participation->getPerson()->getId(); - } - )->first(); - } else { - $newParticipations[] = $participation; - } - } - - // this is where the function redirect depending on valid participation - - if (!isset($newParticipations)) { - // if we do not have nay participants, redirect to event view - $this->addFlash('error', $this->get('translator')->trans( - 'None of the requested people may participate ' - . 'the event: they are maybe already participating.')); - - return $this->redirectToRoute('chill_event__event_show', array( - 'event_id' => $request->query->getInt('event_id', 0) - )); - } elseif (count($newParticipations) > 1) { - // if we have multiple participations, show a form with multiple participations - $form = $this->createCreateFormMultiple($newParticipations); - return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', array( - 'form' => $form->createView(), - 'participations' => $newParticipations, - 'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() - )); - } else { - // if we have only one participation, show the same form than for single participation - $form = $this->createCreateForm($participation); - - return $this->render('ChillEventBundle:Participation:new.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation, - 'ignored_participations' => isset($ignoredParticipations) ? $ignoredParticipations : array() - )); - - } - } - /** - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ public function createAction(Request $request) { // test the request is correct try { $this->testRequest($request); - } catch (\RuntimeException $ex) { + } catch (RuntimeException $ex) { $this->logger->warning($ex->getMessage()); - + return (new Response()) ->setStatusCode(Response::HTTP_BAD_REQUEST) ->setContent($ex->getMessage()); } - + // forward to other action $single = $request->query->has('person_id'); $multiple = $request->query->has('persons_ids'); - - if ($single === true) { + + if (true === $single) { return $this->createSingle($request); } - - if ($multiple === true) { - + + if (true === $multiple) { return $this->createMultiple($request); } - + // at this point, we miss the required fields. Throw an error return (new Response()) ->setStatusCode(Response::HTTP_BAD_REQUEST) - ->setContent("You must provide either 'person_id' or " + ->setContent("You must provide either 'person_id' or " . "'persons_ids' argument in query"); } - - /** - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function createSingle(Request $request) - { - $participation = $this->handleRequest($request, new Participation(), false); - - $this->denyAccessUnlessGranted(ParticipationVoter::CREATE, - $participation, 'The user is not allowed to create this participation'); - - $form = $this->createCreateForm($participation); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - - $em->persist($participation); - $em->flush(); - - $this->addFlash('success', $this->get('translator')->trans( - 'The participation was created' - )); - - if ($request->query->get('return_path')) - { - return $this->redirect($request->query->get('return_path')); - - } else { - return $this->redirectToRoute('chill_event__event_show', array( - 'event_id' => $participation->getEvent()->getId() - )); - } - - } - - return $this->render('ChillEventBundle:Participation:new.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation - )); - } - - /** - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function createMultiple(Request $request) - { - $participations = $this->handleRequest($request, new Participation(), true); - - foreach($participations as $participation) { - $this->denyAccessUnlessGranted(ParticipationVoter::CREATE, - $participation, 'The user is not allowed to create this participation'); - } - - $form = $this->createCreateFormMultiple($participations); - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $data = $form->getData(); - - foreach($data['participations'] as $participation) { - $em->persist($participation); - } - - $em->flush(); - - $this->addFlash('success', $this->get('translator')->trans( - 'The participations were created' - )); - - return $this->redirectToRoute('chill_event__event_show', array( - 'event_id' => $participations[0]->getEvent()->getId() - )); - } - - return $this->render('ChillEventBundle:Participation:new.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation - )); - } - - /** - * - * Handle the request to adapt $participation. - * - * If the request is multiple, the $participation object is cloned. - * Limitations: the $participation should not be persisted. - * - * @param Request $request - * @param Participation $participation - * @param boolean $multiple (default false) - * @return Participation|Participations[] return one single participation if $multiple == false - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the event/person is not found - * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException if the user does not have access to event/person - */ - protected function handleRequest( - Request $request, - Participation $participation, - $multiple = false) - { - $em = $this->getDoctrine()->getManager(); - if ($em->contains($participation)) { - throw new \LogicException("The participation object should not be managed by " - . "the object manager using the method ".__METHOD__); - } - - $event_id = $request->query->getInt('event_id', 0); // sf4 check: - // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` - - if ($event_id !== NULL) { - $event = $em->getRepository('ChillEventBundle:Event') - ->find($event_id); - - if ($event === NULL) { - throw $this->createNotFoundException('The event with id '.$event_id.' is not found'); - } - - $this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, - 'The user is not allowed to see the event'); - - $participation->setEvent($event); - } - - // this script should be able to handle multiple, so we translate - // single person_id in an array - $persons_ids = $request->query->has('person_id') ? - [$request->query->getInt('person_id', 0)] // sf4 check: - // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` - : explode(',', $request->query->get('persons_ids')); - $participations = array(); - - foreach($persons_ids as $person_id) { - - // clone if we have to reuse the $participation - $participation = count($persons_ids) > 1 ? clone $participation : $participation; - - if ($person_id !== NULL) { - $person = $em->getRepository('ChillPersonBundle:Person') - ->find($person_id); - if ($person === NULL) { - throw $this->createNotFoundException('The person with id '.$person_id.' is not found'); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, - 'The user is not allowed to see the person'); - - $participation->setPerson($person); - } - - $participations[] = $participation; - } - - return $multiple ? $participations : $participations[0]; - } - /** - * @param Participation $participation * @param null $return_path + * * @return \Symfony\Component\Form\FormInterface */ public function createCreateForm(Participation $participation, $return_path = null) { - - $form = $this->createForm(ParticipationType::class, $participation, array( + $form = $this->createForm(ParticipationType::class, $participation, [ 'event_type' => $participation->getEvent()->getType(), - 'action' => $this->generateUrl('chill_event_participation_create', array( + 'action' => $this->generateUrl('chill_event_participation_create', [ 'return_path' => $return_path, 'event_id' => $participation->getEvent()->getId(), - 'person_id' => $participation->getPerson()->getId() - )) - )); - - $form->add('submit', SubmitType::class, array( - 'label' => 'Create' - )); - + 'person_id' => $participation->getPerson()->getId(), + ]), + ]); + + $form->add('submit', SubmitType::class, [ + 'label' => 'Create', + ]); + return $form; } - + /** - * @param array $participations * @return \Symfony\Component\Form\FormInterface */ public function createCreateFormMultiple(array $participations) { - $form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class, - array('participations' => $participations), array( - 'action' => $this->generateUrl('chill_event_participation_create', array( - 'event_id' => current($participations)->getEvent()->getId(), - 'persons_ids' => implode(',', array_map( - function(Participation $p) { return $p->getPerson()->getId(); }, - $participations)) - ) - ))); - $form->add('participations', CollectionType::class, array( - 'entry_type' => ParticipationType::class, - 'entry_options' => array( - 'event_type' => current($participations)->getEvent()->getType() - ), - ) + $form = $this->createForm( + \Symfony\Component\Form\Extension\Core\Type\FormType::class, + ['participations' => $participations], + [ + 'action' => $this->generateUrl( + 'chill_event_participation_create', + [ + 'event_id' => current($participations)->getEvent()->getId(), + 'persons_ids' => implode(',', array_map( + function (Participation $p) { + return $p->getPerson()->getId(); + }, + $participations + )), + ] + ), ] ); - - $form->add('submit', SubmitType::class, array( - 'label' => 'Create' - )); - + $form->add( + 'participations', + CollectionType::class, + [ + 'entry_type' => ParticipationType::class, + 'entry_options' => [ + 'event_type' => current($participations)->getEvent()->getType(), + ], + ] + ); + + $form->add('submit', SubmitType::class, [ + 'label' => 'Create', + ]); + return $form; } - + /** - * show an edit form for the participation with the given id. - * - * @param int $participation_id - * @return \Symfony\Component\HttpFoundation\Response - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the participation is not found - * @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException if the user is not allowed to edit the participation - */ - public function editAction($participation_id) - { - /* @var $participation Participation */ - $participation = $this->getDoctrine()->getManager() - ->getRepository('ChillEventBundle:Participation') - ->find($participation_id); - - if ($participation === NULL) { - throw $this->createNotFoundException('The participation is not found'); - } - - $this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation, - 'You are not allowed to edit this participation'); - - $form = $this->createEditForm($participation); - - return $this->render('ChillEventBundle:Participation:edit.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation - )); - } - - /** - * @param $participation_id - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function updateAction($participation_id, Request $request) - { - /* @var $participation Participation */ - $participation = $this->getDoctrine()->getManager() - ->getRepository('ChillEventBundle:Participation') - ->find($participation_id); - - if ($participation === NULL) { - throw $this->createNotFoundException('The participation is not found'); - } - - $this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation, - 'You are not allowed to edit this participation'); - - $form = $this->createEditForm($participation); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - - $em->flush(); - - $this->addFlash('success', $this->get('translator')->trans( - 'The participation was updated' - )); - - return $this->redirectToRoute('chill_event__event_show', array( - 'event_id' => $participation->getEvent()->getId() - )); - - } - - return $this->render('ChillEventBundle:Participation:edit.html.twig', array( - 'form' => $form->createView(), - 'participation' => $participation - )); - } - - /** - * - * @param Participation $participation * @return \Symfony\Component\Form\FormInterface */ public function createEditForm(Participation $participation) { - $form = $this->createForm(ParticipationType::class, $participation, array( + $form = $this->createForm(ParticipationType::class, $participation, [ 'event_type' => $participation->getEvent()->getType(), - 'action' => $this->generateUrl('chill_event_participation_update', array( - 'participation_id' => $participation->getId() - )) - )); - - $form->add('submit', SubmitType::class, array( - 'label' => 'Edit' - )); - - return $form; - } - - /** - * show a form to edit multiple participation for the same event. - * - * @param int $event_id - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function editMultipleAction($event_id) - { - $event = $this->getDoctrine()->getRepository('ChillEventBundle:Event') - ->find($event_id); - - if ($event === null) { - throw $this->createNotFoundException("The event with id $event_id is not found"); - } - - // check for ACL, on Event level and on Participation Level - $this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, "You are not allowed " - . "to see this event"); - foreach ($event->getParticipations() as $participation) { - $this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation, - "You are not allowed to update participation with id ".$participation->getId()); - } - - - switch ($event->getParticipations()->count()) { - - case 0: - // if there aren't any participation, redirect to the 'show' view with an add flash - $this->addFlash('warning', $this->get('translator') - ->trans( "There are no participation to edit for this event")); + 'action' => $this->generateUrl('chill_event_participation_update', [ + 'participation_id' => $participation->getId(), + ]), + ]); + + $form->add('submit', SubmitType::class, [ + 'label' => 'Edit', + ]); - return $this->redirectToRoute('chill_event__event_show', - array('event_id' => $event->getId())); - - case 1: - // redirect to the form for a single participation - return $this->redirectToRoute('chill_event_participation_edit', array( - 'participation_id' => $event->getParticipations()->current()->getId() - )); - } - - $form = $this->createEditFormMultiple($event->getParticipations(), $event); - - return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', array( - 'event' => $event, - 'participations' => $event->getParticipations(), - 'form' => $form->createView() - )); - } - - public function updateMultipleAction($event_id, Request $request) - { - /* @var $event \Chill\EventBundle\Entity\Event */ - $event = $this->getDoctrine()->getRepository('ChillEventBundle:Event') - ->find($event_id); - - if ($event === null) { - throw $this->createNotFoundException("The event with id $event_id is not found"); - } - - $this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, "You are not allowed " - . "to see this event"); - foreach ($event->getParticipations() as $participation) { - $this->denyAccessUnlessGranted(ParticipationVoter::UPDATE, $participation, - "You are not allowed to update participation with id ".$participation->getId()); - } - - $form = $this->createEditFormMultiple($event->getParticipations(), $event); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->getDoctrine()->getManager()->flush(); - - $this->addFlash('success', $this->get('translator')->trans("The participations " - . "have been successfully updated.")); - - return $this->redirectToRoute('chill_event__event_show', - array('event_id' => $event->getId())); - } - - return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', array( - 'event' => $event, - 'participations' => $event->getParticipations(), - 'form' => $form->createView() - )); - } - - /** - * @param ArrayIterator $participations - * @param Event $event - * @return \Symfony\Component\Form\FormInterface - */ - protected function createEditFormMultiple(ArrayIterator $participations, Event $event) - { - $form = $this->createForm(\Symfony\Component\Form\Extension\Core\Type\FormType::class, - array('participations' => $participations), array( - 'method' => 'POST', - 'action' => $this->generateUrl('chill_event_participation_update_multiple', array( - 'event_id' => $event->getId() - )) - )); - - $form->add('participations', CollectionType::class, array( - 'entry_type' => ParticipationType::class, - 'entry_options' => array( - 'event_type' => $event->getType() - ), - ) - ); - - $form->add('submit', SubmitType::class, array( - 'label' => 'Update' - )); - return $form; } - + /** - * @param integer $participation_id - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function createMultiple(Request $request) + { + $participations = $this->handleRequest($request, new Participation(), true); + + foreach ($participations as $participation) { + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' + ); + } + + $form = $this->createCreateFormMultiple($participations); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $data = $form->getData(); + + foreach ($data['participations'] as $participation) { + $em->persist($participation); + } + + $em->flush(); + + $this->addFlash('success', $this->get('translator')->trans( + 'The participations were created' + )); + + return $this->redirectToRoute('chill_event__event_show', [ + 'event_id' => $participations[0]->getEvent()->getId(), + ]); + } + + return $this->render('ChillEventBundle:Participation:new.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + ]); + } + + /** + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function createSingle(Request $request) + { + $participation = $this->handleRequest($request, new Participation(), false); + + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' + ); + + $form = $this->createCreateForm($participation); + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + + $em->persist($participation); + $em->flush(); + + $this->addFlash('success', $this->get('translator')->trans( + 'The participation was created' + )); + + if ($request->query->get('return_path')) { + return $this->redirect($request->query->get('return_path')); + } + + return $this->redirectToRoute('chill_event__event_show', [ + 'event_id' => $participation->getEvent()->getId(), + ]); + } + + return $this->render('ChillEventBundle:Participation:new.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + ]); + } + + /** + * @param int $participation_id + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ public function deleteAction($participation_id, Request $request) { $em = $this->getDoctrine()->getManager(); $participation = $em->getRepository('ChillEventBundle:Participation')->findOneBy([ - 'id' => $participation_id + 'id' => $participation_id, ]); - - if (! $participation) { + + if (!$participation) { throw $this->createNotFoundException('Unable to find participation.'); } - + /** @var Event $event */ $event = $participation->getEvent(); - + $form = $this->createDeleteForm($participation_id); - + if ($request->getMethod() === Request::METHOD_DELETE) { $form->handleRequest($request); - + if ($form->isValid()) { - $em->remove($participation); $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans("The participation has been sucessfully removed") + + $this->addFlash( + 'success', + $this->get('translator') + ->trans('The participation has been sucessfully removed') ); - + return $this->redirectToRoute('chill_event__event_show', [ - 'event_id' => $event->getId() + 'event_id' => $event->getId(), ]); } } + return $this->render('ChillEventBundle:Participation:confirm_delete.html.twig', [ 'event_id' => $event->getId(), - 'delete_form' => $form->createView() + 'delete_form' => $form->createView(), ]); - } - + + /** + * show an edit form for the participation with the given id. + * + * @param int $participation_id + * + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the participation is not found + * @throws \Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException if the user is not allowed to edit the participation + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function editAction($participation_id) + { + /* @var $participation Participation */ + $participation = $this->getDoctrine()->getManager() + ->getRepository('ChillEventBundle:Participation') + ->find($participation_id); + + if (null === $participation) { + throw $this->createNotFoundException('The participation is not found'); + } + + $this->denyAccessUnlessGranted( + ParticipationVoter::UPDATE, + $participation, + 'You are not allowed to edit this participation' + ); + + $form = $this->createEditForm($participation); + + return $this->render('ChillEventBundle:Participation:edit.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + ]); + } + + /** + * show a form to edit multiple participation for the same event. + * + * @param int $event_id + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function editMultipleAction($event_id) + { + $event = $this->getDoctrine()->getRepository('ChillEventBundle:Event') + ->find($event_id); + + if (null === $event) { + throw $this->createNotFoundException("The event with id {$event_id} is not found"); + } + + // check for ACL, on Event level and on Participation Level + $this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, 'You are not allowed ' + . 'to see this event'); + + foreach ($event->getParticipations() as $participation) { + $this->denyAccessUnlessGranted( + ParticipationVoter::UPDATE, + $participation, + 'You are not allowed to update participation with id ' . $participation->getId() + ); + } + + switch ($event->getParticipations()->count()) { + case 0: + // if there aren't any participation, redirect to the 'show' view with an add flash + $this->addFlash('warning', $this->get('translator') + ->trans('There are no participation to edit for this event')); + + return $this->redirectToRoute( + 'chill_event__event_show', + ['event_id' => $event->getId()] + ); + + case 1: + // redirect to the form for a single participation + return $this->redirectToRoute('chill_event_participation_edit', [ + 'participation_id' => $event->getParticipations()->current()->getId(), + ]); + } + + $form = $this->createEditFormMultiple($event->getParticipations(), $event); + + return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', [ + 'event' => $event, + 'participations' => $event->getParticipations(), + 'form' => $form->createView(), + ]); + } + + /** + * Show a form to add a participation. + * + * This function parse the person_id / persons_ids query argument + * and decide if it should process a single or multiple participation. Depending + * on this, the appropriate layout and form. + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function newAction(Request $request) + { + // test the request is correct + try { + $this->testRequest($request); + } catch (RuntimeException $ex) { + $this->logger->warning($ex->getMessage()); + + return (new Response()) + ->setStatusCode(Response::HTTP_BAD_REQUEST) + ->setContent($ex->getMessage()); + } + + // forward to other action + $single = $request->query->has('person_id'); + $multiple = $request->query->has('persons_ids'); + + if (true === $single) { + return $this->newSingle($request); + } + + if (true === $multiple) { + return $this->newMultiple($request); + } + + // at this point, we miss the required fields. Throw an error + return (new Response()) + ->setStatusCode(Response::HTTP_BAD_REQUEST) + ->setContent("You must provide either 'person_id' or " + . "'persons_ids' argument in query"); + } + /** * @param $participation_id + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function updateAction($participation_id, Request $request) + { + /* @var $participation Participation */ + $participation = $this->getDoctrine()->getManager() + ->getRepository('ChillEventBundle:Participation') + ->find($participation_id); + + if (null === $participation) { + throw $this->createNotFoundException('The participation is not found'); + } + + $this->denyAccessUnlessGranted( + ParticipationVoter::UPDATE, + $participation, + 'You are not allowed to edit this participation' + ); + + $form = $this->createEditForm($participation); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + + $em->flush(); + + $this->addFlash('success', $this->get('translator')->trans( + 'The participation was updated' + )); + + return $this->redirectToRoute('chill_event__event_show', [ + 'event_id' => $participation->getEvent()->getId(), + ]); + } + + return $this->render('ChillEventBundle:Participation:edit.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + ]); + } + + public function updateMultipleAction($event_id, Request $request) + { + /* @var $event \Chill\EventBundle\Entity\Event */ + $event = $this->getDoctrine()->getRepository('ChillEventBundle:Event') + ->find($event_id); + + if (null === $event) { + throw $this->createNotFoundException("The event with id {$event_id} is not found"); + } + + $this->denyAccessUnlessGranted('CHILL_EVENT_SEE', $event, 'You are not allowed ' + . 'to see this event'); + + foreach ($event->getParticipations() as $participation) { + $this->denyAccessUnlessGranted( + ParticipationVoter::UPDATE, + $participation, + 'You are not allowed to update participation with id ' . $participation->getId() + ); + } + + $form = $this->createEditFormMultiple($event->getParticipations(), $event); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->getDoctrine()->getManager()->flush(); + + $this->addFlash('success', $this->get('translator')->trans('The participations ' + . 'have been successfully updated.')); + + return $this->redirectToRoute( + 'chill_event__event_show', + ['event_id' => $event->getId()] + ); + } + + return $this->render('ChillEventBundle:Participation:edit-multiple.html.twig', [ + 'event' => $event, + 'participations' => $event->getParticipations(), + 'form' => $form->createView(), + ]); + } + + /** + * @return \Symfony\Component\Form\FormInterface + */ + protected function createEditFormMultiple(ArrayIterator $participations, Event $event) + { + $form = $this->createForm( + \Symfony\Component\Form\Extension\Core\Type\FormType::class, + ['participations' => $participations], + [ + 'method' => 'POST', + 'action' => $this->generateUrl('chill_event_participation_update_multiple', [ + 'event_id' => $event->getId(), + ]), + ] + ); + + $form->add( + 'participations', + CollectionType::class, + [ + 'entry_type' => ParticipationType::class, + 'entry_options' => [ + 'event_type' => $event->getType(), + ], + ] + ); + + $form->add('submit', SubmitType::class, [ + 'label' => 'Update', + ]); + + return $form; + } + + /** + * Handle the request to adapt $participation. + * + * If the request is multiple, the $participation object is cloned. + * Limitations: the $participation should not be persisted. + * + * @param bool $multiple (default false) + * + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the event/person is not found + * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException if the user does not have access to event/person + * + * @return Participation|Participations[] return one single participation if $multiple == false + */ + protected function handleRequest( + Request $request, + Participation $participation, + $multiple = false + ) { + $em = $this->getDoctrine()->getManager(); + + if ($em->contains($participation)) { + throw new LogicException('The participation object should not be managed by ' + . 'the object manager using the method ' . __METHOD__); + } + + $event_id = $request->query->getInt('event_id', 0); // sf4 check: + // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` + + if (null !== $event_id) { + $event = $em->getRepository('ChillEventBundle:Event') + ->find($event_id); + + if (null === $event) { + throw $this->createNotFoundException('The event with id ' . $event_id . ' is not found'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_EVENT_SEE', + $event, + 'The user is not allowed to see the event' + ); + + $participation->setEvent($event); + } + + // this script should be able to handle multiple, so we translate + // single person_id in an array + $persons_ids = $request->query->has('person_id') ? + [$request->query->getInt('person_id', 0)] // sf4 check: + // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` + : explode(',', $request->query->get('persons_ids')); + $participations = []; + + foreach ($persons_ids as $person_id) { + // clone if we have to reuse the $participation + $participation = count($persons_ids) > 1 ? clone $participation : $participation; + + if (null !== $person_id) { + $person = $em->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if (null === $person) { + throw $this->createNotFoundException('The person with id ' . $person_id . ' is not found'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_SEE', + $person, + 'The user is not allowed to see the person' + ); + + $participation->setPerson($person); + } + + $participations[] = $participation; + } + + return $multiple ? $participations : $participations[0]; + } + + /** + * Show a form with multiple participation. + * + * If a person is already participating on the event (if a participation with + * the same person is associated with the event), the participation is ignored. + * + * If all but one participation is ignored, the page show the same response + * than the newSingle function. + * + * If all participations must be ignored, an error is shown and the method redirects + * to the event 'show' view with an appropriate flash message. + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + protected function newMultiple(Request $request) + { + $participations = $this->handleRequest($request, new Participation(), true); + + foreach ($participations as $i => $participation) { + // check for authorization + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' + ); + + // create a collection of person's id participating to the event + /* @var $peopleParticipating \Doctrine\Common\Collections\ArrayCollection */ + $peopleParticipating = $peopleParticipating ?? + $participation->getEvent()->getParticipations()->map( + function (Participation $p) { + return $p->getPerson()->getId(); + } + ); + // check that the user is not already in the event + if ($peopleParticipating->contains($participation->getPerson()->getId())) { + $ignoredParticipations[] = $participation + ->getEvent()->getParticipations()->filter( + function (Participation $p) use ($participation) { + return $p->getPerson()->getId() === $participation->getPerson()->getId(); + } + )->first(); + } else { + $newParticipations[] = $participation; + } + } + + // this is where the function redirect depending on valid participation + + if (!isset($newParticipations)) { + // if we do not have nay participants, redirect to event view + $this->addFlash('error', $this->get('translator')->trans( + 'None of the requested people may participate ' + . 'the event: they are maybe already participating.' + )); + + return $this->redirectToRoute('chill_event__event_show', [ + 'event_id' => $request->query->getInt('event_id', 0), + ]); + } + + if (count($newParticipations) > 1) { + // if we have multiple participations, show a form with multiple participations + $form = $this->createCreateFormMultiple($newParticipations); + + return $this->render('ChillEventBundle:Participation:new-multiple.html.twig', [ + 'form' => $form->createView(), + 'participations' => $newParticipations, + 'ignored_participations' => $ignoredParticipations ?? [], + ]); + } + // if we have only one participation, show the same form than for single participation + $form = $this->createCreateForm($participation); + + return $this->render('ChillEventBundle:Participation:new.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + 'ignored_participations' => $ignoredParticipations ?? [], + ]); + } + + /** + * Show a form with single participation. + * + * @return Response + */ + protected function newSingle(Request $request) + { + $returnPath = $request->query->get('return_path') ? + $request->query->get('return_path') : null; + + $participation = $this->handleRequest($request, new Participation(), false); + + $this->denyAccessUnlessGranted( + ParticipationVoter::CREATE, + $participation, + 'The user is not allowed to create this participation' + ); + + $form = $this->createCreateForm($participation, $returnPath); + + return $this->render('ChillEventBundle:Participation:new.html.twig', [ + 'form' => $form->createView(), + 'participation' => $participation, + 'ignored_participations' => [], // this is required, see self::newMultiple + ]); + } + + /** + * Test that the query parameters are valid :. + * + * - an `event_id` is existing ; + * - `person_id` and `persons_ids` are **not** both present ; + * - `persons_id` is correct (contains only numbers and a ','. + * + * @throws RuntimeException if an error is detected + */ + protected function testRequest(Request $request) + { + $single = $request->query->has('person_id'); + $multiple = $request->query->has('persons_ids'); + + if (true === $single and true === $multiple) { + // we are not allowed to have both person_id and persons_ids + throw new RuntimeException("You are not allow to provide both 'person_id' and " + . "'persons_ids' simulaneously"); + } + + if (true === $multiple) { + $persons_ids = $request->query->get('persons_ids'); + + if (!preg_match('/^([0-9]{1,},{0,1}){1,}[0-9]{0,}$/', $persons_ids)) { + throw new RuntimeException('The persons_ids value should ' + . "contains int separated by ','"); + } + } + + // check for event_id - this could be removed later + if ($request->query->has('event_id') === false) { + throw new RuntimeException('You must provide an event_id'); + } + } + + /** + * @param $participation_id + * * @return \Symfony\Component\Form\FormInterface */ private function createDeleteForm($participation_id) { return $this->createFormBuilder() ->setAction($this->generateUrl('chill_event_participation_delete', [ - 'participation_id' => $participation_id + 'participation_id' => $participation_id, ])) ->setMethod('DELETE') ->add('submit', SubmitType::class, ['label' => 'Delete']) - ->getForm() - ; + ->getForm(); } - } diff --git a/src/Bundle/ChillEventBundle/Controller/RoleController.php b/src/Bundle/ChillEventBundle/Controller/RoleController.php index 103729934..3df68ff1f 100644 --- a/src/Bundle/ChillEventBundle/Controller/RoleController.php +++ b/src/Bundle/ChillEventBundle/Controller/RoleController.php @@ -1,38 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillEventBundle:Role')->findAll(); - - return $this->render('ChillEventBundle:Role:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new Role entity. - * */ public function createAction(Request $request) { @@ -45,149 +34,22 @@ class RoleController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_event_admin_role', - array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl( + 'chill_event_admin_role', + ['id' => $entity->getId()] + )); } - return $this->render('ChillEventBundle:Role:new.html.twig', array( + return $this->render('ChillEventBundle:Role:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); + 'form' => $form->createView(), + ]); } - /** - * Creates a form to create a Role entity. - * - * @param Role $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Role $entity) - { - $form = $this->createForm(RoleType::class, $entity, array( - 'action' => $this->generateUrl('chill_event_admin_role_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new Role entity. - * - */ - public function newAction() - { - $entity = new Role(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillEventBundle:Role:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Role entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Role')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Role entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:Role:show.html.twig', array( - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Displays a form to edit an existing Role entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Role')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Role entity.'); - } - - $editForm = $this->createEditForm($entity); - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:Role:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Creates a form to edit a Role entity. - * - * @param Role $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Role $entity) - { - $form = $this->createForm(RoleType::class, $entity, array( - 'action' => $this->generateUrl('chill_event_admin_role_update', - array('id' => $entity->getId())), - 'method' => 'PUT', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - /** - * Edits an existing Role entity. - * - */ - public function updateAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Role')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Role entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - $em->flush(); - - return $this->redirect($this->generateUrl('chill_event_admin_role', - array('id' => $id))); - } - - return $this->render('ChillEventBundle:Role:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } /** * Deletes a Role entity. * + * @param mixed $id */ public function deleteAction(Request $request, $id) { @@ -209,6 +71,136 @@ class RoleController extends AbstractController return $this->redirect($this->generateUrl('chill_event_admin_role')); } + /** + * Displays a form to edit an existing Role entity. + * + * @param mixed $id + */ + public function editAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Role')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Role entity.'); + } + + $editForm = $this->createEditForm($entity); + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:Role:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Lists all Role entities. + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + + $entities = $em->getRepository('ChillEventBundle:Role')->findAll(); + + return $this->render('ChillEventBundle:Role:index.html.twig', [ + 'entities' => $entities, + ]); + } + + /** + * Displays a form to create a new Role entity. + */ + public function newAction() + { + $entity = new Role(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillEventBundle:Role:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Role entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Role')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Role entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:Role:show.html.twig', [ + 'entity' => $entity, + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Edits an existing Role entity. + * + * @param mixed $id + */ + public function updateAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Role')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Role entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + $editForm = $this->createEditForm($entity); + $editForm->handleRequest($request); + + if ($editForm->isValid()) { + $em->flush(); + + return $this->redirect($this->generateUrl( + 'chill_event_admin_role', + ['id' => $id] + )); + } + + return $this->render('ChillEventBundle:Role:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Creates a form to create a Role entity. + * + * @param Role $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(Role $entity) + { + $form = $this->createForm(RoleType::class, $entity, [ + 'action' => $this->generateUrl('chill_event_admin_role_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + /** * Creates a form to delete a Role entity by id. * @@ -219,10 +211,31 @@ class RoleController extends AbstractController private function createDeleteForm($id) { return $this->createFormBuilder() - ->setAction($this->generateUrl('chill_event_admin_role_delete', array('id' => $id))) + ->setAction($this->generateUrl('chill_event_admin_role_delete', ['id' => $id])) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + /** + * Creates a form to edit a Role entity. + * + * @param Role $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Role $entity) + { + $form = $this->createForm(RoleType::class, $entity, [ + 'action' => $this->generateUrl( + 'chill_event_admin_role_update', + ['id' => $entity->getId()] + ), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillEventBundle/Controller/StatusController.php b/src/Bundle/ChillEventBundle/Controller/StatusController.php index e5861aa80..45d2cf1ff 100644 --- a/src/Bundle/ChillEventBundle/Controller/StatusController.php +++ b/src/Bundle/ChillEventBundle/Controller/StatusController.php @@ -1,39 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillEventBundle:Status')->findAll(); - - return $this->render('ChillEventBundle:Status:index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new Status entity. - * */ public function createAction(Request $request) { @@ -46,146 +34,19 @@ class StatusController extends AbstractController $em->persist($entity); $em->flush(); - return $this->redirect($this->generateUrl('chill_event_admin_status', array('id' => $entity->getId()))); + return $this->redirect($this->generateUrl('chill_event_admin_status', ['id' => $entity->getId()])); } - return $this->render('ChillEventBundle:Status:new.html.twig', array( + return $this->render('ChillEventBundle:Status:new.html.twig', [ 'entity' => $entity, - 'form' => $form->createView(), - )); + 'form' => $form->createView(), + ]); } - /** - * Creates a form to create a Status entity. - * - * @param Status $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Status $entity) - { - $form = $this->createForm(StatusType::class, $entity, array( - 'action' => $this->generateUrl('chill_event_admin_status_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new Status entity. - * - */ - public function newAction() - { - $entity = new Status(); - $form = $this->createCreateForm($entity); - - return $this->render('ChillEventBundle:Status:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Status entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Status')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Status entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:Status:show.html.twig', array( - 'entity' => $entity, - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Displays a form to edit an existing Status entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Status')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Status entity.'); - } - - $editForm = $this->createEditForm($entity); - $deleteForm = $this->createDeleteForm($id); - - return $this->render('ChillEventBundle:Status:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } - - /** - * Creates a form to edit a Status entity. - * - * @param Status $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Status $entity) - { - $form = $this->createForm(StatusType::class, $entity, array( - 'action' => $this->generateUrl('chill_event_admin_status_update', array('id' => $entity->getId())), - 'method' => 'PUT', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - /** - * Edits an existing Status entity. - * - */ - public function updateAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); - - $entity = $em->getRepository('ChillEventBundle:Status')->find($id); - - if (!$entity) { - throw $this->createNotFoundException('Unable to find Status entity.'); - } - - $deleteForm = $this->createDeleteForm($id); - $editForm = $this->createEditForm($entity); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - $em->flush(); - - return $this->redirect($this->generateUrl('chill_event_admin_status', array('id' => $id))); - } - - return $this->render('ChillEventBundle:Status:edit.html.twig', array( - 'entity' => $entity, - 'edit_form' => $editForm->createView(), - 'delete_form' => $deleteForm->createView(), - )); - } /** * Deletes a Status entity. * + * @param mixed $id */ public function deleteAction(Request $request, $id) { @@ -207,6 +68,133 @@ class StatusController extends AbstractController return $this->redirect($this->generateUrl('chill_event_admin_status')); } + /** + * Displays a form to edit an existing Status entity. + * + * @param mixed $id + */ + public function editAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Status')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Status entity.'); + } + + $editForm = $this->createEditForm($entity); + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:Status:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Lists all Status entities. + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + + $entities = $em->getRepository('ChillEventBundle:Status')->findAll(); + + return $this->render('ChillEventBundle:Status:index.html.twig', [ + 'entities' => $entities, + ]); + } + + /** + * Displays a form to create a new Status entity. + */ + public function newAction() + { + $entity = new Status(); + $form = $this->createCreateForm($entity); + + return $this->render('ChillEventBundle:Status:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Status entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Status')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Status entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + + return $this->render('ChillEventBundle:Status:show.html.twig', [ + 'entity' => $entity, + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Edits an existing Status entity. + * + * @param mixed $id + */ + public function updateAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + + $entity = $em->getRepository('ChillEventBundle:Status')->find($id); + + if (!$entity) { + throw $this->createNotFoundException('Unable to find Status entity.'); + } + + $deleteForm = $this->createDeleteForm($id); + $editForm = $this->createEditForm($entity); + $editForm->handleRequest($request); + + if ($editForm->isValid()) { + $em->flush(); + + return $this->redirect($this->generateUrl('chill_event_admin_status', ['id' => $id])); + } + + return $this->render('ChillEventBundle:Status:edit.html.twig', [ + 'entity' => $entity, + 'edit_form' => $editForm->createView(), + 'delete_form' => $deleteForm->createView(), + ]); + } + + /** + * Creates a form to create a Status entity. + * + * @param Status $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(Status $entity) + { + $form = $this->createForm(StatusType::class, $entity, [ + 'action' => $this->generateUrl('chill_event_admin_status_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + /** * Creates a form to delete a Status entity by id. * @@ -217,10 +205,28 @@ class StatusController extends AbstractController private function createDeleteForm($id) { return $this->createFormBuilder() - ->setAction($this->generateUrl('chill_event_admin_status_delete', array('id' => $id))) + ->setAction($this->generateUrl('chill_event_admin_status_delete', ['id' => $id])) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + } + + /** + * Creates a form to edit a Status entity. + * + * @param Status $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Status $entity) + { + $form = $this->createForm(StatusType::class, $entity, [ + 'action' => $this->generateUrl('chill_event_admin_status_update', ['id' => $entity->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadEventTypes.php b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadEventTypes.php index 148582ca3..5caacd188 100644 --- a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadEventTypes.php +++ b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadEventTypes.php @@ -1,25 +1,28 @@ - * @author Champs Libres */ class LoadEventTypes extends AbstractFixture implements OrderedFixtureInterface { - public static $refs = array(); - + public static $refs = []; + public function getOrder() { return 30000; @@ -31,256 +34,224 @@ class LoadEventTypes extends AbstractFixture implements OrderedFixtureInterface * Echange de savoirs */ $type = (new EventType()) - ->setActive(true) - ->setName(array('fr' => 'Échange de savoirs', 'en' => 'Exchange of knowledge')) - ; + ->setActive(true) + ->setName(['fr' => 'Échange de savoirs', 'en' => 'Exchange of knowledge']); $manager->persist($type); - + $this->addReference('event_type_knowledge', $type); self::$refs[] = 'event_type_knowledge'; - + $role = (new Role()) - ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setActive(true) + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - + $role = (new Role()) - ->setActive(true) - ->setName(array('fr' => 'Animateur')) - ->setType($type); + ->setActive(true) + ->setName(['fr' => 'Animateur']) + ->setType($type); $manager->persist($role); - + $status = (new Status()) - ->setActive(true) - ->setName(array('fr' => 'Inscrit')) - ->setType($type); + ->setActive(true) + ->setName(['fr' => 'Inscrit']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) - ->setActive(true) - ->setName(array('fr' => 'Présent')) - ->setType($type) - ; + ->setActive(true) + ->setName(['fr' => 'Présent']) + ->setType($type); $manager->persist($status); - + /* * Formation */ $type = (new EventType()) - ->setActive(true) - ->setName(array('fr' => 'Formation', 'en' => 'Course', 'nl' => 'Opleiding')) - ; + ->setActive(true) + ->setName(['fr' => 'Formation', 'en' => 'Course', 'nl' => 'Opleiding']); $manager->persist($type); - + $this->addReference('event_type_course', $type); self::$refs[] = 'event_type_course'; - + $role = (new Role()) - ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setActive(true) + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - - $status = (new Status()) - ->setActive(true) - ->setName(array('fr' => 'Inscrit')) - ->setType($type) - ; - $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'En liste d\'attente')) - ->setType($type) - ; + ->setName(['fr' => 'Inscrit']) + ->setType($type); $manager->persist($status); - + + $status = (new Status()) + ->setActive(true) + ->setName(['fr' => 'En liste d\'attente']) + ->setType($type); + $manager->persist($status); + /* * Visite */ $type = (new EventType()) ->setActive(true) - ->setName(array('fr' => 'Visite', 'en' => 'Visit')) - ; + ->setName(['fr' => 'Visite', 'en' => 'Visit']); $manager->persist($type); - + $this->addReference('event_type_visit', $type); self::$refs[] = 'event_type_visit'; - + $role = (new Role()) ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Présent')) - ->setType($type) - ; + ->setName(['fr' => 'Présent']) + ->setType($type); $manager->persist($status); $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Absent')) - ->setType($type) - ; + ->setName(['fr' => 'Absent']) + ->setType($type); $manager->persist($status); $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Excusé')) - ->setType($type) - ; + ->setName(['fr' => 'Excusé']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Inscrit')) - ->setType($type) - ; + ->setName(['fr' => 'Inscrit']) + ->setType($type); $manager->persist($status); - + /* * Réunion */ $type = (new EventType()) ->setActive(true) - ->setName(array('fr' => 'Réunion', 'en' => 'Meeting')) - ; + ->setName(['fr' => 'Réunion', 'en' => 'Meeting']); $manager->persist($type); - + $this->addReference('event_type_meeting', $type); self::$refs[] = 'event_type_meeting'; - + $role = (new Role()) ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Présent')) - ->setType($type) - ; + ->setName(['fr' => 'Présent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Absent')) - ->setType($type) - ; + ->setName(['fr' => 'Absent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Excusé')) - ->setType($type) - ; + ->setName(['fr' => 'Excusé']) + ->setType($type); $manager->persist($status); - + /* * Atelier */ $type = (new EventType()) ->setActive(true) - ->setName(array('fr' => 'Atelier', 'en' => 'Workshop')) - ; + ->setName(['fr' => 'Atelier', 'en' => 'Workshop']); $manager->persist($type); - + $this->addReference('event_type_workshop', $type); self::$refs[] = 'event_type_workshop'; - + $role = (new Role()) ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Présent')) - ->setType($type) - ; + ->setName(['fr' => 'Présent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Absent')) - ->setType($type) - ; + ->setName(['fr' => 'Absent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Excusé')) - ->setType($type) - ; + ->setName(['fr' => 'Excusé']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Inscrit')) - ->setType($type) - ; + ->setName(['fr' => 'Inscrit']) + ->setType($type); $manager->persist($status); - - + /* * Séance d'info */ $type = (new EventType()) ->setActive(true) - ->setName(array('fr' => "Séance d'info", 'en' => 'Info')) - ; + ->setName(['fr' => "Séance d'info", 'en' => 'Info']); $manager->persist($type); - + $this->addReference('event_type_info', $type); self::$refs[] = 'event_type_info'; - + $role = (new Role()) ->setActive(true) - ->setName(array('fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant')) - ->setType($type) - ; + ->setName(['fr' => 'Participant', 'nl' => 'Deelneemer', 'en' => 'Participant']) + ->setType($type); $manager->persist($role); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Présent')) - ->setType($type) - ; + ->setName(['fr' => 'Présent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Absent')) - ->setType($type) - ; + ->setName(['fr' => 'Absent']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Excusé')) - ->setType($type) - ; + ->setName(['fr' => 'Excusé']) + ->setType($type); $manager->persist($status); - + $status = (new Status()) ->setActive(true) - ->setName(array('fr' => 'Inscrit')) - ->setType($type) - ; + ->setName(['fr' => 'Inscrit']) + ->setType($type); $manager->persist($status); - - + $manager->flush(); } } diff --git a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadParticipation.php b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadParticipation.php index b89937abe..bd0234740 100644 --- a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadParticipation.php +++ b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadParticipation.php @@ -1,34 +1,60 @@ - * @author Champs Libres + * Load Events and Participation. */ class LoadParticipation extends AbstractFixture implements OrderedFixtureInterface { /** - * * @var \Faker\Generator */ protected $faker; - + public function __construct() { $this->faker = \Faker\Factory::create('fr_FR'); } - + + public function createEvents(Center $center, ObjectManager $manager) + { + $expectedNumber = 20; + $events = []; + + for ($i = 0; $i < $expectedNumber; ++$i) { + $event = (new Event()) + ->setDate($this->faker->dateTimeBetween('-2 years', '+6 months')) + ->setName($this->faker->words(rand(2, 4), true)) + ->setType($this->getReference(LoadEventTypes::$refs[array_rand(LoadEventTypes::$refs)])) + ->setCenter($center) + ->setCircle( + $this->getReference( + LoadScopes::$references[array_rand(LoadScopes::$references)] + ) + ); + $manager->persist($event); + $events[] = $event; + } + + return $events; + } + public function getOrder() { return 30010; @@ -37,62 +63,36 @@ class LoadParticipation extends AbstractFixture implements OrderedFixtureInterfa public function load(ObjectManager $manager) { $centers = $manager->getRepository('ChillMainBundle:Center') - ->findAll(); - - foreach($centers as $center) { - + ->findAll(); + + foreach ($centers as $center) { $people = $manager->getRepository('ChillPersonBundle:Person') - ->findBy(array('center' => $center)); + ->findBy(['center' => $center]); $events = $this->createEvents($center, $manager); /* @var $person \Chill\PersonBundle\Entity\Person */ foreach ($people as $person) { - $nb = rand(0,3); - - for ($i=0; $i<$nb; $i++) { + $nb = rand(0, 3); + + for ($i = 0; $i < $nb; ++$i) { $event = $events[array_rand($events)]; $role = $event->getType()->getRoles()->get( - array_rand($event->getType()->getRoles()->toArray())); + array_rand($event->getType()->getRoles()->toArray()) + ); $status = $event->getType()->getStatuses()->get( - array_rand($event->getType()->getStatuses()->toArray())); + array_rand($event->getType()->getStatuses()->toArray()) + ); $participation = (new Participation()) - ->setPerson($person) - ->setRole($role) - ->setStatus($status) - ->setEvent($event) - ; + ->setPerson($person) + ->setRole($role) + ->setStatus($status) + ->setEvent($event); $manager->persist($participation); } } } - + $manager->flush(); - - - } - - public function createEvents(Center $center, ObjectManager $manager) - { - $expectedNumber = 20; - $events = array(); - - for($i=0; $i<$expectedNumber; $i++) { - $event = (new Event()) - ->setDate($this->faker->dateTimeBetween('-2 years', '+6 months')) - ->setName($this->faker->words(rand(2,4), true)) - ->setType($this->getReference(LoadEventTypes::$refs[array_rand(LoadEventTypes::$refs)])) - ->setCenter($center) - ->setCircle( - $this->getReference( - LoadScopes::$references[array_rand(LoadScopes::$references)] - ) - ) - ; - $manager->persist($event); - $events[] = $event; - } - - return $events; } } diff --git a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php index 7ef753e52..45790c458 100644 --- a/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php +++ b/src/Bundle/ChillEventBundle/DataFixtures/ORM/LoadRolesACL.php @@ -1,45 +1,37 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ - namespace Chill\EventBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\Entity\RoleScope; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; use Doctrine\Persistence\ObjectManager; /** - * Add roles to existing groups - * - * @author Julien Fastré - * @author Champs Libres + * Add roles to existing groups. */ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface { + public function getOrder() + { + return 30011; + } + public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); - foreach (LoadScopes::$references as $scopeRef){ + + foreach (LoadScopes::$references as $scopeRef) { $scope = $this->getReference($scopeRef); //create permission group switch ($permissionsGroup->getName()) { @@ -47,40 +39,46 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface if ($scope->getName()['en'] === 'administrative') { break 2; // we do not want any power on administrative } + break; + case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], ['administrative', 'social'])) { break 2; // we do not want any power on social or administrative - } + } + break; } - - printf("Adding CHILL_EVENT_UPDATE & CHILL_EVENT_CREATE " - . "& CHILL_EVENT_PARTICIPATION_UPDATE & CHILL_EVENT_PARTICIPATION_CREATE " - . "& CHILL_EVENT_SEE & CHILL_EVENT_SEE_DETAILS " - . "to %s " - . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); - + + printf( + 'Adding CHILL_EVENT_UPDATE & CHILL_EVENT_CREATE ' + . '& CHILL_EVENT_PARTICIPATION_UPDATE & CHILL_EVENT_PARTICIPATION_CREATE ' + . '& CHILL_EVENT_SEE & CHILL_EVENT_SEE_DETAILS ' + . 'to %s ' + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), + $scope->getName()['en'] + ); + $roleScopeUpdate = (new RoleScope()) - ->setRole('CHILL_EVENT_UPDATE') - ->setScope($scope); + ->setRole('CHILL_EVENT_UPDATE') + ->setScope($scope); $roleScopeUpdate2 = (new RoleScope()) - ->setRole('CHILL_EVENT_PARTICIPATION_UPDATE') - ->setScope($scope); + ->setRole('CHILL_EVENT_PARTICIPATION_UPDATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $permissionsGroup->addRoleScope($roleScopeUpdate2); - + $roleScopeCreate = (new RoleScope()) - ->setRole('CHILL_EVENT_CREATE') - ->setScope($scope); + ->setRole('CHILL_EVENT_CREATE') + ->setScope($scope); $roleScopeCreate2 = (new RoleScope()) - ->setRole('CHILL_EVENT_PARTICIPATION_CREATE') - ->setScope($scope); + ->setRole('CHILL_EVENT_PARTICIPATION_CREATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $permissionsGroup->addRoleScope($roleScopeCreate2); - + $roleScopeSee = (new RoleScope()) ->setRole('CHILL_EVENT_SEE') ->setScope($scope); @@ -89,7 +87,7 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeSee); $permissionsGroup->addRoleScope($roleScopeSee2); - + $manager->persist($roleScopeUpdate); $manager->persist($roleScopeUpdate2); $manager->persist($roleScopeCreate); @@ -97,15 +95,8 @@ class LoadRolesACL extends AbstractFixture implements OrderedFixtureInterface $manager->persist($roleScopeSee); $manager->persist($roleScopeSee2); } - } - + $manager->flush(); } - - public function getOrder() - { - return 30011; - } - } diff --git a/src/Bundle/ChillEventBundle/DependencyInjection/ChillEventExtension.php b/src/Bundle/ChillEventBundle/DependencyInjection/ChillEventExtension.php index 639d3068d..dc20a27a5 100644 --- a/src/Bundle/ChillEventBundle/DependencyInjection/ChillEventExtension.php +++ b/src/Bundle/ChillEventBundle/DependencyInjection/ChillEventExtension.php @@ -1,30 +1,34 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/authorization.yaml'); $loader->load('services/controller.yaml'); @@ -35,46 +39,42 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface $loader->load('services/search.yaml'); $loader->load('services/timeline.yaml'); } - - /* (non-PHPdoc) - * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() - */ - public function prepend(ContainerBuilder $container) + + /* (non-PHPdoc) + * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() + */ + public function prepend(ContainerBuilder $container) { $this->prependAuthorization($container); $this->prependRoute($container); } - + /** - * add route to route loader for chill - * - * @param ContainerBuilder $container + * add authorization hierarchy. + */ + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + EventVoter::SEE_DETAILS => [EventVoter::SEE], + EventVoter::UPDATE => [EventVoter::SEE_DETAILS], + EventVoter::CREATE => [EventVoter::SEE_DETAILS], + ], + ]); + } + + /** + * add route to route loader for chill. */ protected function prependRoute(ContainerBuilder $container) { //add routes for custom bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillEventBundle/config/routes.yaml' - ) - ) - )); - } - - /** - * add authorization hierarchy - * - * @param ContainerBuilder $container - */ - protected function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - EventVoter::SEE_DETAILS => array(EventVoter::SEE), - EventVoter::UPDATE => array(EventVoter::SEE_DETAILS), - EventVoter::CREATE => array(EventVoter::SEE_DETAILS) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillEventBundle/config/routes.yaml', + ], + ], + ]); } } diff --git a/src/Bundle/ChillEventBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillEventBundle/DependencyInjection/Configuration.php index 14cbddafe..2d90f006b 100644 --- a/src/Bundle/ChillEventBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillEventBundle/DependencyInjection/Configuration.php @@ -1,20 +1,24 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Chill\MainBundle\Entity\User; +use ArrayIterator; use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\Scope; -use Doctrine\Common\Collections\Collection; -use Doctrine\Common\Collections\ArrayCollection; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; +use DateTime; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; +use Traversable; /** - * Class Event + * Class Event. * - * @package Chill\EventBundle\Entity * @ORM\Entity(repositoryClass="Chill\EventBundle\Repository\EventRepository") * @ORM\Table(name="chill_event_event") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class Event implements HasCenterInterface, HasScopeInterface { /** - * @var integer + * @var Center + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center") + */ + private $center; + + /** + * @var Scope + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") + */ + private $circle; + + /** + * @var DateTime + * @ORM\Column(type="datetime") + */ + private $date; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -49,6 +57,12 @@ class Event implements HasCenterInterface, HasScopeInterface */ private $id; + /** + * @var User + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") + */ + private $moderator; + /** * @var string * @ORM\Column(type="string", length=150) @@ -56,48 +70,19 @@ class Event implements HasCenterInterface, HasScopeInterface private $name; /** - * @var \DateTime - * @ORM\Column(type="datetime") + * @var Participation + * @ORM\OneToMany( + * targetEntity="Chill\EventBundle\Entity\Participation", + * mappedBy="event") */ - private $date; - + private $participations; + /** - * - * @var Center - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Center") - */ - private $center; - - /** - * * @var EventType * @ORM\ManyToOne(targetEntity="Chill\EventBundle\Entity\EventType") */ private $type; - - /** - * - * @var Scope - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") - */ - private $circle; - - /** - * @var Participation - * @ORM\OneToMany( - * targetEntity="Chill\EventBundle\Entity\Participation", - * mappedBy="event") - */ - private $participations; - - /** - * - * @var User - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") - */ - private $moderator; - - + /** * Event constructor. */ @@ -107,130 +92,8 @@ class Event implements HasCenterInterface, HasScopeInterface } /** - * Get id + * Add participation. * - * @return integer - */ - public function getId() - { - return $this->id; - } - - /** - * Set label - * - * @param string $label - * @return Event - */ - public function setName($label) - { - $this->name = $label; - - return $this; - } - - /** - * Get label - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Set date - * - * @param \DateTime $date - * @return Event - */ - public function setDate(\DateTime $date) - { - $this->date = $date; - - return $this; - } - - /** - * Get date - * - * @return \DateTime - */ - public function getDate() - { - return $this->date; - } - - /** - * @param Center $center - * @return $this - */ - public function setCenter(Center $center) - { - $this->center = $center; - - return $this; - } - - /** - * @return EventType - */ - public function getType() - { - return $this->type; - } - - /** - * @param EventType $type - * @return $this - */ - public function setType(EventType $type) - { - $this->type = $type; - return $this; - } - - /** - * @return Center - */ - public function getCenter() - { - return $this->center; - } - - /** - * @return Scope - */ - public function getCircle() - { - return $this->circle; - } - - /** - * @param Scope $circle - * @return $this - */ - public function setCircle(\Chill\MainBundle\Entity\Scope $circle) - { - $this->circle = $circle; - return $this; - } - - /** - * @deprecated - * @return Scope - */ - public function getScope() - { - return $this->getCircle(); - } - - - /** - * Add participation - * - * @param Participation $participation * @return Event */ public function addParticipation(Participation $participation) @@ -241,40 +104,41 @@ class Event implements HasCenterInterface, HasScopeInterface } /** - * Remove participation - * - * @param Participation $participation + * @return Center */ - public function removeParticipation(Participation $participation) + public function getCenter() { - $this->participations->removeElement($participation); + return $this->center; } - + /** - * @return \ArrayIterator|\Traversable|Collection + * @return Scope */ - public function getParticipations() + public function getCircle() { - return $this->getParticipationsOrdered(); + return $this->circle; } - + /** - * Sort Collection of Participations + * Get date. * - * @return \ArrayIterator|\Traversable + * @return DateTime */ - public function getParticipationsOrdered() { - - $iterator = $this->participations->getIterator(); - - $iterator->uasort(function($first, $second) - { - return strnatcasecmp($first->getPerson()->getFirstName(), $second->getPerson()->getFirstName()); - }); - - return $iterator; + public function getDate() + { + return $this->date; } - + + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + /** * @return int */ @@ -282,14 +146,132 @@ class Event implements HasCenterInterface, HasScopeInterface { return $this->moderator; } - + + /** + * Get label. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return ArrayIterator|Collection|Traversable + */ + public function getParticipations() + { + return $this->getParticipationsOrdered(); + } + + /** + * Sort Collection of Participations. + * + * @return ArrayIterator|Traversable + */ + public function getParticipationsOrdered() + { + $iterator = $this->participations->getIterator(); + + $iterator->uasort(function ($first, $second) { + return strnatcasecmp($first->getPerson()->getFirstName(), $second->getPerson()->getFirstName()); + }); + + return $iterator; + } + + /** + * @deprecated + * + * @return Scope + */ + public function getScope() + { + return $this->getCircle(); + } + + /** + * @return EventType + */ + public function getType() + { + return $this->type; + } + + /** + * Remove participation. + */ + public function removeParticipation(Participation $participation) + { + $this->participations->removeElement($participation); + } + + /** + * @return $this + */ + public function setCenter(Center $center) + { + $this->center = $center; + + return $this; + } + + /** + * @return $this + */ + public function setCircle(Scope $circle) + { + $this->circle = $circle; + + return $this; + } + + /** + * Set date. + * + * @return Event + */ + public function setDate(DateTime $date) + { + $this->date = $date; + + return $this; + } + /** * @param int $moderator + * * @return Event */ public function setModerator($moderator) { $this->moderator = $moderator; + + return $this; + } + + /** + * Set label. + * + * @param string $label + * + * @return Event + */ + public function setName($label) + { + $this->name = $label; + + return $this; + } + + /** + * @return $this + */ + public function setType(EventType $type) + { + $this->type = $type; + return $this; } } diff --git a/src/Bundle/ChillEventBundle/Entity/EventType.php b/src/Bundle/ChillEventBundle/Entity/EventType.php index 8c67d8c81..e86d58bde 100644 --- a/src/Bundle/ChillEventBundle/Entity/EventType.php +++ b/src/Bundle/ChillEventBundle/Entity/EventType.php @@ -1,42 +1,35 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * Class EventType + * Class EventType. * - * @package Chill\EventBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_event_event_type") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class EventType { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -50,17 +43,11 @@ class EventType */ private $name; - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active; - /** * @var Collection * @ORM\OneToMany( * targetEntity="Chill\EventBundle\Entity\Role", - * mappedBy="type") + * mappedBy="type") */ private $roles; @@ -68,12 +55,12 @@ class EventType * @var Collection * @ORM\OneToMany( * targetEntity="Chill\EventBundle\Entity\Status", - * mappedBy="type") + * mappedBy="type") */ private $statuses; /** - * Constructor + * Constructor. */ public function __construct() { @@ -82,65 +69,8 @@ class EventType } /** - * Get id + * Add role. * - * @return integer - */ - public function getId() - { - return $this->id; - } - - /** - * Set label - * - * @param array $label - * @return EventType - */ - public function setName($label) - { - $this->name = $label; - - return $this; - } - - /** - * Get label - * - * @return array - */ - public function getName() - { - return $this->name; - } - - /** - * Set active - * - * @param boolean $active - * @return EventType - */ - public function setActive($active) - { - $this->active = $active; - - return $this; - } - - /** - * Get active - * - * @return boolean - */ - public function getActive() - { - return $this->active; - } - - /** - * Add role - * - * @param Role $role * @return EventType */ public function addRole(Role $role) @@ -151,29 +81,8 @@ class EventType } /** - * Remove role + * Add status. * - * @param Role $role - */ - public function removeRole(Role $role) - { - $this->roles->removeElement($role); - } - - /** - * Get roles - * - * @return Collection - */ - public function getRoles() - { - return $this->roles; - } - - /** - * Add status - * - * @param Status $status * @return EventType */ public function addStatus(Status $status) @@ -184,17 +93,47 @@ class EventType } /** - * Remove status + * Get active. * - * @param Status $status + * @return bool */ - public function removeStatus(Status $status) + public function getActive() { - $this->statuses->removeElement($status); + return $this->active; } /** - * Get statuses + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get label. + * + * @return array + */ + public function getName() + { + return $this->name; + } + + /** + * Get roles. + * + * @return Collection + */ + public function getRoles() + { + return $this->roles; + } + + /** + * Get statuses. * * @return Collection */ @@ -202,4 +141,48 @@ class EventType { return $this->statuses; } + + /** + * Remove role. + */ + public function removeRole(Role $role) + { + $this->roles->removeElement($role); + } + + /** + * Remove status. + */ + public function removeStatus(Status $status) + { + $this->statuses->removeElement($status); + } + + /** + * Set active. + * + * @param bool $active + * + * @return EventType + */ + public function setActive($active) + { + $this->active = $active; + + return $this; + } + + /** + * Set label. + * + * @param array $label + * + * @return EventType + */ + public function setName($label) + { + $this->name = $label; + + return $this; + } } diff --git a/src/Bundle/ChillEventBundle/Entity/Participation.php b/src/Bundle/ChillEventBundle/Entity/Participation.php index d578db863..e5493f1a6 100644 --- a/src/Bundle/ChillEventBundle/Entity/Participation.php +++ b/src/Bundle/ChillEventBundle/Entity/Participation.php @@ -1,47 +1,45 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Entity; -use Doctrine\ORM\Mapping as ORM; +use ArrayAccess; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\HasCenterInterface; +use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\Scope; use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\HasScopeInterface; -use Chill\MainBundle\Entity\HasCenterInterface; +use DateTime; +use Doctrine\ORM\Mapping as ORM; +use RuntimeException; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** - * Class Participation + * Class Participation. * - * @package Chill\EventBundle\Entity * @ORM\Entity( - * repositoryClass="Chill\EventBundle\Repository\ParticipationRepository") + * repositoryClass="Chill\EventBundle\Repository\ParticipationRepository") * @ORM\Table(name="chill_event_participation") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ -class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAccess +class Participation implements HasCenterInterface, HasScopeInterface, ArrayAccess { /** - * @var integer + * @var Event + * @ORM\ManyToOne( + * targetEntity="Chill\EventBundle\Entity\Event", + * inversedBy="participations") + */ + private $event; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -50,18 +48,10 @@ class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAcce private $id; /** - * @var \DateTime + * @var DateTime * @ORM\Column(type="datetime") */ private $lastUpdate; - - /** - * @var Event - * @ORM\ManyToOne( - * targetEntity="Chill\EventBundle\Entity\Event", - * inversedBy="participations") - */ - private $event; /** * @var Person @@ -81,60 +71,21 @@ class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAcce */ private $status; - /** - * Get id - * - * @return integer + * @return Center */ - public function getId() + public function getCenter() { - return $this->id; - } - - /** - * Set lastUpdate - * - * @param \DateTime $lastUpdate - * @return Participation - */ - protected function update() - { - $this->lastUpdate = new \DateTime('now'); - - return $this; - } - - /** - * Get lastUpdate - * - * @return \DateTime - */ - public function getLastUpdate() - { - return $this->lastUpdate; - } - - - /** - * Set event - * - * @param Event $event - * @return Participation - */ - public function setEvent(Event $event = null) - { - if ($this->event !== $event) { - $this->update(); + if ($this->getEvent() === null) { + throw new RuntimeException('The event is not linked with this instance. ' + . 'You should initialize the event with a valid center before.'); } - - $this->event = $event; - return $this; + return $this->getEvent()->getCenter(); } /** - * Get event + * Get event. * * @return Event */ @@ -144,24 +95,27 @@ class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAcce } /** - * Set person + * Get id. * - * @param Person $person - * @return Participation + * @return int */ - public function setPerson(Person $person = null) + public function getId() { - if ($person !== $this->person) { - $this->update(); - } - - $this->person = $person; - - return $this; + return $this->id; } /** - * Get person + * Get lastUpdate. + * + * @return DateTime + */ + public function getLastUpdate() + { + return $this->lastUpdate; + } + + /** + * Get person. * * @return Person */ @@ -171,12 +125,194 @@ class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAcce } /** - * Set role + * Get role. + * + * @return Role + */ + public function getRole() + { + return $this->role; + } + + /** + * @return Scope + */ + public function getScope() + { + if ($this->getEvent() === null) { + throw new RuntimeException('The event is not linked with this instance. ' + . 'You should initialize the event with a valid center before.'); + } + + return $this->getEvent()->getCircle(); + } + + /** + * Get status. + * + * @return Status + */ + public function getStatus() + { + return $this->status; + } + + /** + * Check that :. + * + * - the role can be associated with this event type + * - the status can be associated with this event type + */ + public function isConsistent(ExecutionContextInterface $context) + { + if ($this->getEvent() === null || $this->getRole() === null || $this->getStatus() === null) { + return; + } + + if ( + $this->getRole()->getType()->getId() !== + $this->getEvent()->getType()->getId() + ) { + $context->buildViolation('The role is not allowed with this event type') + ->atPath('role') + ->addViolation(); + } + + if ( + $this->getStatus()->getType()->getId() !== + $this->getEvent()->getType()->getId() + ) { + $context->buildViolation('The status is not allowed with this event type') + ->atPath('status') + ->addViolation(); + } + } + + /** + * @param mixed $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return in_array($offset, [ + 'person', 'role', 'status', 'event', + ]); + } + + /** + * @param mixed $offset + * + * @return Event|mixed|Person|Role|Status + */ + public function offsetGet($offset) + { + switch ($offset) { + case 'person': + return $this->getPerson(); + + break; + + case 'role': + return $this->getRole(); + + break; + + case 'status': + return $this->getStatus(); + + break; + + case 'event': + return $this->getEvent(); + + break; + } + } + + /** + * @param mixed $offset + * @param mixed $value + * + * @return Participation|void + */ + public function offsetSet($offset, $value) + { + switch ($offset) { + case 'person': + return $this->setPerson($value); + + break; + + case 'role': + return $this->setRole($value); + + break; + + case 'status': + return $this->setStatus($value); + + break; + + case 'event': + return $this->setEvent($value); + + break; + } + } + + /** + * @param mixed $offset + */ + public function offsetUnset($offset) + { + $this->offsetSet($offset, null); + } + + /** + * Set event. + * + * @param Event $event * - * @param Role $role * @return Participation */ - public function setRole(Role $role = null) + public function setEvent(?Event $event = null) + { + if ($this->event !== $event) { + $this->update(); + } + + $this->event = $event; + + return $this; + } + + /** + * Set person. + * + * @param Person $person + * + * @return Participation + */ + public function setPerson(?Person $person = null) + { + if ($person !== $this->person) { + $this->update(); + } + + $this->person = $person; + + return $this; + } + + /** + * Set role. + * + * @param Role $role + * + * @return Participation + */ + public function setRole(?Role $role = null) { if ($role !== $this->role) { $this->update(); @@ -187,160 +323,32 @@ class Participation implements HasCenterInterface, HasScopeInterface, \ArrayAcce } /** - * Get role - * - * @return Role - */ - public function getRole() - { - return $this->role; - } - - /** - * Set status + * Set status. * * @param Status $status + * * @return Participation */ - public function setStatus(Status $status = null) + public function setStatus(?Status $status = null) { if ($this->status !== $status) { $this->update(); } - + $this->status = $status; return $this; } /** - * Get status + * Set lastUpdate. * - * @return Status + * @return Participation */ - public function getStatus() + protected function update() { - return $this->status; - } - - /** - * @return Center - */ - public function getCenter() - { - if ($this->getEvent() === NULL) { - throw new \RuntimeException('The event is not linked with this instance. ' - . 'You should initialize the event with a valid center before.'); - } - - return $this->getEvent()->getCenter(); - } - - /** - * @return Scope - */ - public function getScope() - { - if ($this->getEvent() === NULL) { - throw new \RuntimeException('The event is not linked with this instance. ' - . 'You should initialize the event with a valid center before.'); - } - - return $this->getEvent()->getCircle(); - } - - /** - * Check that : - * - * - the role can be associated with this event type - * - the status can be associated with this event type - * - * @param ExecutionContextInterface $context - */ - public function isConsistent(ExecutionContextInterface $context) - { - - if ($this->getEvent() === NULL || $this->getRole() === NULL || $this->getStatus() === NULL) { - return; - } - - if ($this->getRole()->getType()->getId() !== - $this->getEvent()->getType()->getId()) { - $context->buildViolation('The role is not allowed with this event type') - ->atPath('role') - ->addViolation(); - } - - if ($this->getStatus()->getType()->getId() !== - $this->getEvent()->getType()->getId()) { - $context->buildViolation('The status is not allowed with this event type') - ->atPath('status') - ->addViolation(); - } - } - - /** - * @param mixed $offset - * @return bool - */ - public function offsetExists($offset) - { - return in_array($offset, array( - 'person', 'role', 'status', 'event' - )); - } - - /** - * @param mixed $offset - * @return Event|Role|Status|Person|mixed - */ - public function offsetGet($offset) - { - switch ($offset) { - case 'person': - return $this->getPerson(); - break; - case 'role': - return $this->getRole(); - break; - case 'status': - return $this->getStatus(); - break; - case 'event': - return $this->getEvent(); - break; - } - } - - /** - * @param mixed $offset - * @param mixed $value - * @return Participation|void - */ - public function offsetSet($offset, $value) - { - switch($offset) { - case 'person': - return $this->setPerson($value); - break; - case 'role': - return $this->setRole($value); - break; - case 'status': - return $this->setStatus($value); - break; - case 'event': - return $this->setEvent($value); - break; - } - } - - /** - * @param mixed $offset - */ - public function offsetUnset($offset) - { - $this->offsetSet($offset, null); - } + $this->lastUpdate = new DateTime('now'); + return $this; + } } diff --git a/src/Bundle/ChillEventBundle/Entity/Role.php b/src/Bundle/ChillEventBundle/Entity/Role.php index cf7d3a243..cc975be32 100644 --- a/src/Bundle/ChillEventBundle/Entity/Role.php +++ b/src/Bundle/ChillEventBundle/Entity/Role.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Entity; @@ -24,17 +12,22 @@ namespace Chill\EventBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Class Role + * Class Role. * - * @package Chill\EventBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_event_role") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class Role { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -48,25 +41,28 @@ class Role */ private $name; - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active; - /** * @var EventType * @ORM\ManyToOne( * targetEntity="Chill\EventBundle\Entity\EventType", - * inversedBy="roles") + * inversedBy="roles") */ private $type; + /** + * Get active. + * + * @return bool + */ + public function getActive() + { + return $this->active; + } /** - * Get id + * Get id. * - * @return integer + * @return int */ public function getId() { @@ -74,20 +70,7 @@ class Role } /** - * Set label - * - * @param array $label - * @return Role - */ - public function setName($label) - { - $this->name = $label; - - return $this; - } - - /** - * Get label + * Get label. * * @return array */ @@ -97,9 +80,20 @@ class Role } /** - * Set active + * Get type. + * + * @return EventType + */ + public function getType() + { + return $this->type; + } + + /** + * Set active. + * + * @param bool $active * - * @param boolean $active * @return Role */ public function setActive($active) @@ -110,36 +104,30 @@ class Role } /** - * Get active + * Set label. * - * @return boolean - */ - public function getActive() - { - return $this->active; - } - - - /** - * Set type + * @param array $label * - * @param EventType $type * @return Role */ - public function setType(EventType $type = null) + public function setName($label) { - $this->type = $type; + $this->name = $label; return $this; } /** - * Get type + * Set type. * - * @return EventType + * @param EventType $type + * + * @return Role */ - public function getType() + public function setType(?EventType $type = null) { - return $this->type; + $this->type = $type; + + return $this; } } diff --git a/src/Bundle/ChillEventBundle/Entity/Status.php b/src/Bundle/ChillEventBundle/Entity/Status.php index a88bff5c4..c39663cc1 100644 --- a/src/Bundle/ChillEventBundle/Entity/Status.php +++ b/src/Bundle/ChillEventBundle/Entity/Status.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Entity; @@ -24,49 +12,57 @@ namespace Chill\EventBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Class Status + * Class Status. * - * @package Chill\EventBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_event_status") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class Status { /** - * @var integer + * @var bool + * @ORM\Column(type="boolean") + */ + private $active; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + /** * @var array * @ORM\Column(type="json_array") */ private $name; - - /** - * @var boolean - * @ORM\Column(type="boolean") - */ - private $active; - + /** * @var EventType * @ORM\ManyToOne( * targetEntity="Chill\EventBundle\Entity\EventType", - * inversedBy="statuses") + * inversedBy="statuses") */ private $type; + /** + * Get active. + * + * @return bool + */ + public function getActive() + { + return $this->active; + } /** - * Get id + * Get id. * - * @return integer + * @return int */ public function getId() { @@ -74,20 +70,7 @@ class Status } /** - * Set label - * - * @param array $name - * @return Status - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get label + * Get label. * * @return array */ @@ -96,11 +79,21 @@ class Status return $this->name; } + /** + * Get type. + * + * @return EventType + */ + public function getType() + { + return $this->type; + } /** - * Set active + * Set active. + * + * @param bool $active * - * @param boolean $active * @return Status */ public function setActive($active) @@ -111,36 +104,30 @@ class Status } /** - * Get active + * Set label. * - * @return boolean - */ - public function getActive() - { - return $this->active; - } - - - /** - * Set type + * @param array $name * - * @param EventType $type * @return Status */ - public function setType(EventType $type = null) + public function setName($name) { - $this->type = $type; + $this->name = $name; return $this; } /** - * Get type + * Set type. * - * @return EventType + * @param EventType $type + * + * @return Status */ - public function getType() + public function setType(?EventType $type = null) { - return $this->type; + $this->type = $type; + + return $this; } } diff --git a/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php b/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php index c96e541f7..31a4a9040 100644 --- a/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php +++ b/src/Bundle/ChillEventBundle/Form/ChoiceLoader/EventChoiceLoader.php @@ -1,29 +1,24 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form\ChoiceLoader; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; -use Doctrine\ORM\EntityRepository; use Chill\EventBundle\Entity\Event; +use Doctrine\ORM\EntityRepository; +use RuntimeException; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; +use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; -/*** +use function call_user_func; +use function in_array; + +/* * Class EventChoiceLoader * * @package Chill\EventBundle\Form\ChoiceLoader @@ -31,38 +26,101 @@ use Chill\EventBundle\Entity\Event; */ class EventChoiceLoader implements ChoiceLoaderInterface { - - /** - * @var EntityRepository - */ - protected $eventRepository; - - /** - * @var array - */ - protected $lazyLoadedEvents = []; - /** * @var array */ protected $centers = []; - + + /** + * @var EntityRepository + */ + protected $eventRepository; + + /** + * @var array + */ + protected $lazyLoadedEvents = []; + /** * EventChoiceLoader constructor. - * - * @param EntityRepository $eventRepository - * @param array|null $centers */ public function __construct( EntityRepository $eventRepository, - array $centers = null + ?array $centers = null ) { $this->eventRepository = $eventRepository; - if (NULL !== $centers) { + + if (null !== $centers) { $this->centers = $centers; } } - + + /** + * @param null $value + */ + public function loadChoiceList($value = null): ChoiceListInterface + { + return new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( + $this->lazyLoadedEvents, + function (Event $p) use ($value) { + return call_user_func($value, $p); + } + ); + } + + /** + * @param null $value + * + * @return array + */ + public function loadChoicesForValues(array $values, $value = null) + { + $choices = []; + + foreach ($values as $value) { + if (empty($value)) { + continue; + } + + $event = $this->eventRepository->find($value); + + if ( + $this->hasCenterFilter() + && !in_array($event->getCenter(), $this->centers) + ) { + throw new RuntimeException('chosen an event not in correct center'); + } + + $choices[] = $event; + } + + return $choices; + } + + /** + * @param null $value + * + * @return array|string[] + */ + public function loadValuesForChoices(array $choices, $value = null) + { + $values = []; + + foreach ($choices as $choice) { + if (null === $choice) { + $values[] = null; + + continue; + } + + $id = call_user_func($value, $choice); + $values[] = $id; + $this->lazyLoadedEvents[$id] = $choice; + } + + return $values; + } + /** * @return bool */ @@ -70,69 +128,4 @@ class EventChoiceLoader implements ChoiceLoaderInterface { return count($this->centers) > 0; } - - /** - * @param null $value - * @return ChoiceListInterface - */ - public function loadChoiceList($value = null): ChoiceListInterface - { - $list = new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( - $this->lazyLoadedEvents, - function(Event $p) use ($value) { - return \call_user_func($value, $p); - }); - - return $list; - } - - /** - * @param array $values - * @param null $value - * @return array - */ - public function loadChoicesForValues(array $values, $value = null) - { - $choices = []; - - foreach($values as $value) { - if (empty($value)) { - continue; - } - - $event = $this->eventRepository->find($value); - - if ($this->hasCenterFilter() && - !\in_array($event->getCenter(), $this->centers)) { - throw new \RuntimeException("chosen an event not in correct center"); - } - - $choices[] = $event; - } - - return $choices; - } - - /** - * @param array $choices - * @param null $value - * @return array|string[] - */ - public function loadValuesForChoices(array $choices, $value = null) - { - $values = []; - - foreach ($choices as $choice) { - if (NULL === $choice) { - $values[] = null; - continue; - } - - $id = \call_user_func($value, $choice); - $values[] = $id; - $this->lazyLoadedEvents[$id] = $choice; - } - return $values; - } - } diff --git a/src/Bundle/ChillEventBundle/Form/EventType.php b/src/Bundle/ChillEventBundle/Form/EventType.php index ed1265620..9861c0915 100644 --- a/src/Bundle/ChillEventBundle/Form/EventType.php +++ b/src/Bundle/ChillEventBundle/Form/EventType.php @@ -1,91 +1,63 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form; use Chill\EventBundle\Form\Type\PickEventTypeType; -use Chill\MainBundle\Form\Type\ScopePickerType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Form\Type\ChillDateTimeType; +use Chill\MainBundle\Form\Type\ScopePickerType; use Chill\MainBundle\Form\Type\UserPickerType; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; class EventType extends AbstractType { - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name') - ->add('date', ChillDateTimeType::class, array( - 'required' => true - )) - ->add('circle', ScopePickerType::class, [ - 'center' => $options['center'], - 'role' => $options['role'] + ->add('date', ChillDateTimeType::class, [ + 'required' => true, ]) - ->add('type', PickEventTypeType::class, array( - 'placeholder' => 'Pick a type of event', - 'attr' => array( - 'class' => '' - ) - )) - ->add('moderator', UserPickerType::class, array( + ->add('circle', ScopePickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'], + 'role' => $options['role'], + ]) + ->add('type', PickEventTypeType::class, [ + 'placeholder' => 'Pick a type of event', + 'attr' => [ + 'class' => '', + ], + ]) + ->add('moderator', UserPickerType::class, [ + 'center' => $options['center'], + 'role' => $options['role'], 'placeholder' => 'Pick a moderator', - 'attr' => array( - 'class' => '' - ), - 'required' => false - )) - ; + 'attr' => [ + 'class' => '', + ], + 'required' => false, + ]); } - - /** - * @param OptionsResolver $resolver - */ + public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\EventBundle\Entity\Event' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\EventBundle\Entity\Event', + ]); $resolver - ->setRequired(array('center', 'role')) + ->setRequired(['center', 'role']) ->setAllowedTypes('center', Center::class) - ->setAllowedTypes('role', Role::class) - ; + ->setAllowedTypes('role', Role::class); } /** diff --git a/src/Bundle/ChillEventBundle/Form/EventTypeType.php b/src/Bundle/ChillEventBundle/Form/EventTypeType.php index b72a9f186..8e95057dd 100644 --- a/src/Bundle/ChillEventBundle/Form/EventTypeType.php +++ b/src/Bundle/ChillEventBundle/Form/EventTypeType.php @@ -1,34 +1,26 @@ add('name', TranslatableStringFormType::class) - ->add('active') - ; - } - - /** - * @param OptionsResolverInterface $resolver - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'data_class' => 'Chill\EventBundle\Entity\EventType' - )); + ->add('active'); } /** @@ -38,4 +30,11 @@ class EventTypeType extends AbstractType { return 'chill_eventbundle_eventtype'; } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Chill\EventBundle\Entity\EventType', + ]); + } } diff --git a/src/Bundle/ChillEventBundle/Form/ParticipationType.php b/src/Bundle/ChillEventBundle/Form/ParticipationType.php index d7186ac91..0f44e641c 100644 --- a/src/Bundle/ChillEventBundle/Form/ParticipationType.php +++ b/src/Bundle/ChillEventBundle/Form/ParticipationType.php @@ -1,76 +1,60 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form; +use Chill\EventBundle\Entity\EventType; +use Chill\EventBundle\Entity\Status; +use Chill\EventBundle\Form\Type\PickRoleType; +use Chill\EventBundle\Form\Type\PickStatusType; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\EventBundle\Entity\EventType; -use Chill\EventBundle\Entity\Status; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Chill\EventBundle\Form\Type\PickRoleType; -use Chill\EventBundle\Form\Type\PickStatusType; /** - * A type to create a participation - * - * If the `event` option is defined, the role will be restricted + * A type to create a participation. * - * @author Julien Fastré + * If the `event` option is defined, the role will be restricted */ class ParticipationType extends AbstractType { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct(TranslatableStringHelper $translatableStringHelper) { $this->translatableStringHelper = $translatableStringHelper; } - + public function buildForm(FormBuilderInterface $builder, array $options) { // local copy of variable for Closure $translatableStringHelper = $this->translatableStringHelper; - + // add role - $builder->add('role', PickRoleType::class, array( - 'event_type' => $options['event_type'] - )); - + $builder->add('role', PickRoleType::class, [ + 'event_type' => $options['event_type'], + ]); + // add a status - $builder->add('status', PickStatusType::class, array( - 'event_type' => $options['event_type'] - )); - + $builder->add('status', PickStatusType::class, [ + 'event_type' => $options['event_type'], + ]); } - + public function configureOptions(OptionsResolver $resolver) { $resolver->setDefined('event_type') - ->setAllowedTypes('event_type', array('null', EventType::class)) - ->setDefault('event_type', 'null'); + ->setAllowedTypes('event_type', ['null', EventType::class]) + ->setDefault('event_type', 'null'); } } diff --git a/src/Bundle/ChillEventBundle/Form/RoleType.php b/src/Bundle/ChillEventBundle/Form/RoleType.php index d3483e917..938648240 100644 --- a/src/Bundle/ChillEventBundle/Form/RoleType.php +++ b/src/Bundle/ChillEventBundle/Form/RoleType.php @@ -1,53 +1,45 @@ translatableStringHelper = $translatableStringHelper; } - - /** - * @param FormBuilderInterface $builder - * @param array $options - */ + public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name', TranslatableStringFormType::class) ->add('active') - ->add('type', EntityType::class, array( + ->add('type', EntityType::class, [ 'class' => EventType::class, - 'choice_label' => function (EventType $e) { + 'choice_label' => function (EventType $e) { return $this->translatableStringHelper->localize($e->getName()); - } - )) - ; - } - - /** - * @param OptionsResolverInterface $resolver - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'data_class' => 'Chill\EventBundle\Entity\Role' - )); + }, + ]); } /** @@ -57,4 +49,11 @@ class RoleType extends AbstractType { return 'chill_eventbundle_role'; } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Chill\EventBundle\Entity\Role', + ]); + } } diff --git a/src/Bundle/ChillEventBundle/Form/StatusType.php b/src/Bundle/ChillEventBundle/Form/StatusType.php index bee55c8c9..1cb97db58 100644 --- a/src/Bundle/ChillEventBundle/Form/StatusType.php +++ b/src/Bundle/ChillEventBundle/Form/StatusType.php @@ -1,36 +1,28 @@ add('name', TranslatableStringFormType::class) ->add('active') - ->add('type', PickEventTypeType::class) - ; - } - - /** - * @param OptionsResolverInterface $resolver - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'data_class' => 'Chill\EventBundle\Entity\Status' - )); + ->add('type', PickEventTypeType::class); } /** @@ -40,4 +32,11 @@ class StatusType extends AbstractType { return 'chill_eventbundle_status'; } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Chill\EventBundle\Entity\Status', + ]); + } } diff --git a/src/Bundle/ChillEventBundle/Form/Type/PickEventType.php b/src/Bundle/ChillEventBundle/Form/Type/PickEventType.php index 9cf8c3f29..b8149acc2 100644 --- a/src/Bundle/ChillEventBundle/Form/Type/PickEventType.php +++ b/src/Bundle/ChillEventBundle/Form/Type/PickEventType.php @@ -1,23 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form\Type; @@ -30,6 +17,7 @@ use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use RuntimeException; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Finder\Exception\AccessDeniedException; use Symfony\Component\Form\AbstractType; @@ -41,47 +29,37 @@ use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Translation\TranslatorInterface; /** - * Class PickEventType - * - * @package Chill\EventBundle\Form\Type - * @author Mathieu Jaumotte jaum_mathieu@collectifs.net + * Class PickEventType. */ class PickEventType extends AbstractType { - - /** - * @var EventRepository - */ - protected $eventRepository; - - /** - * @var User - */ - protected $user; - /** * @var AuthorizationHelper */ protected $authorizationHelper; - + /** - * @var UrlGeneratorInterface + * @var EventRepository */ - protected $urlGenerator; - + protected $eventRepository; + /** * @var TranslatorInterface */ protected $translator; - + + /** + * @var UrlGeneratorInterface + */ + protected $urlGenerator; + + /** + * @var User + */ + protected $user; + /** * PickEventType constructor. - * - * @param EventRepository $eventRepository - * @param TokenStorageInterface $tokenStorage - * @param AuthorizationHelper $authorizationHelper - * @param UrlGeneratorInterface $urlGenerator - * @param TranslatorInterface $translator */ public function __construct( EventRepository $eventRepository, @@ -96,80 +74,69 @@ class PickEventType extends AbstractType $this->urlGenerator = $urlGenerator; $this->translator = $translator; } - - /** - * @param OptionsResolver $resolver - */ - public function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - // add the possibles options for this type - $resolver - ->setDefined('centers') - ->addAllowedTypes('centers', array('array', Center::class, 'null')) - ->setDefault('centers', null) - ; - $resolver - ->setDefined('role') - ->addAllowedTypes('role', array(Role::class, 'null')) - ->setDefault('role', null) - ; - - // add the default options - $resolver->setDefaults(array( - 'class' => Event::class, - 'choice_label' => function(Event $e) { - return $e->getDate()->format('d/m/Y, H:i') . ' → ' . - // $e->getType()->getName()['fr'] . ': ' . // display the type of event - $e->getName(); - }, - 'placeholder' => 'Pick an event', - 'attr' => array('class' => 'select2 '), - 'choice_attr' => function(Event $e) { - return array('data-center' => $e->getCenter()->getId()); - }, - 'choiceloader' => function(Options $options) { - $centers = $this->filterCenters($options); - return new EventChoiceLoader($this->eventRepository, $centers); - } - )); - - } - - /** - * @return null|string - */ - public function getParent() - { - return EntityType::class; - } - - /** - * @param \Symfony\Component\Form\FormView $view - * @param \Symfony\Component\Form\FormInterface $form - * @param array $options - */ + public function buildView(\Symfony\Component\Form\FormView $view, \Symfony\Component\Form\FormInterface $form, array $options) { $view->vars['attr']['data-person-picker'] = true; $view->vars['attr']['data-select-interactive-loading'] = true; $view->vars['attr']['data-search-url'] = $this->urlGenerator - ->generate('chill_main_search', [ 'name' => EventSearch::NAME, '_format' => 'json' ]); + ->generate('chill_main_search', ['name' => EventSearch::NAME, '_format' => 'json']); $view->vars['attr']['data-placeholder'] = $this->translator->trans($options['placeholder']); $view->vars['attr']['data-no-results-label'] = $this->translator->trans('select2.no_results'); $view->vars['attr']['data-error-load-label'] = $this->translator->trans('select2.error_loading'); $view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching'); } - + + public function configureOptions(OptionsResolver $resolver) + { + parent::configureOptions($resolver); + + // add the possibles options for this type + $resolver + ->setDefined('centers') + ->addAllowedTypes('centers', ['array', Center::class, 'null']) + ->setDefault('centers', null); + $resolver + ->setDefined('role') + ->addAllowedTypes('role', [Role::class, 'null']) + ->setDefault('role', null); + + // add the default options + $resolver->setDefaults([ + 'class' => Event::class, + 'choice_label' => function (Event $e) { + return $e->getDate()->format('d/m/Y, H:i') . ' → ' . + // $e->getType()->getName()['fr'] . ': ' . // display the type of event + $e->getName(); + }, + 'placeholder' => 'Pick an event', + 'attr' => ['class' => 'select2 '], + 'choice_attr' => function (Event $e) { + return ['data-center' => $e->getCenter()->getId()]; + }, + 'choiceloader' => function (Options $options) { + $centers = $this->filterCenters($options); + + return new EventChoiceLoader($this->eventRepository, $centers); + }, + ]); + } + + /** + * @return string|null + */ + public function getParent() + { + return EntityType::class; + } + /** - * @param Options $options * @return array */ protected function filterCenters(Options $options) { // option role - if ($options['role'] === NULL) { + if (null === $options['role']) { $centers = array_map( function (GroupCenter $g) { return $g->getCenter(); @@ -184,31 +151,35 @@ class PickEventType extends AbstractType } // option center - if ($options['centers'] === NULL) - { + if (null === $options['centers']) { // we select all selected centers $selectedCenters = $centers; - } else { - $selectedCenters = array(); + $selectedCenters = []; $optionsCenters = is_array($options['centers']) ? - $options['centers'] : array($options['centers']); - + $options['centers'] : [$options['centers']]; + foreach ($optionsCenters as $c) { // check that every member of the array is a center if (!$c instanceof Center) { - throw new \RuntimeException('Every member of the "centers" ' - . 'option must be an instance of '.Center::class); + throw new RuntimeException('Every member of the "centers" ' + . 'option must be an instance of ' . Center::class); } - if (!in_array($c->getId(), array_map( - function(Center $c) { return $c->getId();}, - $centers))) { + + if ( + !in_array($c->getId(), array_map( + function (Center $c) { + return $c->getId(); + }, + $centers + )) + ) { throw new AccessDeniedException('The given center is not reachable'); } $selectedCenters[] = $c; } } + return $selectedCenters; } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillEventBundle/Form/Type/PickEventTypeType.php b/src/Bundle/ChillEventBundle/Form/Type/PickEventTypeType.php index 4821296ae..0511497ec 100644 --- a/src/Bundle/ChillEventBundle/Form/Type/PickEventTypeType.php +++ b/src/Bundle/ChillEventBundle/Form/Type/PickEventTypeType.php @@ -1,38 +1,23 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form\Type; +use Chill\EventBundle\Entity\EventType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Doctrine\ORM\EntityRepository; -use Chill\EventBundle\Entity\EventType; /** - * Description of TranslatableEventType - * - * @author Champs-Libres Coop + * Description of TranslatableEventType. */ class PickEventTypeType extends AbstractType { @@ -40,34 +25,34 @@ class PickEventTypeType extends AbstractType * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct(TranslatableStringHelper $helper) { $this->translatableStringHelper = $helper; } - - public function getParent() - { - return EntityType::class; - } - + public function configureOptions(OptionsResolver $resolver) { $helper = $this->translatableStringHelper; $resolver->setDefaults( - array( + [ 'class' => EventType::class, 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('et') - ->where('et.active = true'); + ->where('et.active = true'); }, 'choice_label' => function (EventType $t) use ($helper) { return $helper->localize($t->getName()); }, 'choice_attrs' => function (EventType $t) { - return array('data-link-category' => $t->getId()); - } - ) + return ['data-link-category' => $t->getId()]; + }, + ] ); } + + public function getParent() + { + return EntityType::class; + } } diff --git a/src/Bundle/ChillEventBundle/Form/Type/PickRoleType.php b/src/Bundle/ChillEventBundle/Form/Type/PickRoleType.php index 545892b98..56da2cb40 100644 --- a/src/Bundle/ChillEventBundle/Form/Type/PickRoleType.php +++ b/src/Bundle/ChillEventBundle/Form/Type/PickRoleType.php @@ -1,149 +1,128 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form\Type; +use Chill\EventBundle\Entity\EventType; +use Chill\EventBundle\Entity\Role; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\EventBundle\Entity\Role; -use Chill\EventBundle\Entity\EventType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Doctrine\ORM\EntityRepository; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Translation\TranslatorInterface; /** - * Allow to pick a choice amongst different choices - * - * @author Julien Fastré - * @author Champs Libres + * Allow to pick a choice amongst different choices. */ class PickRoleType extends AbstractType { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var EntityRepository */ protected $roleRepository; - + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * @var TranslatorInterface + */ + protected $translator; + public function __construct( - TranslatableStringHelper $translatableStringHelper, - TranslatorInterface $translator, - EntityRepository $roleRepository + TranslatableStringHelper $translatableStringHelper, + TranslatorInterface $translator, + EntityRepository $roleRepository ) { $this->translatableStringHelper = $translatableStringHelper; $this->translator = $translator; $this->roleRepository = $roleRepository; } - + public function buildForm(FormBuilderInterface $builder, array $options) { // create copy for easier management $qb = $options['query_builder']; - + if ($options['event_type'] instanceof EventType) { $options['query_builder']->where($qb->expr()->eq('r.type', ':event_type')) - ->setParameter('event_type', $options['event_type']); - } - - if ($options['active_only'] === true) { - $options['query_builder']->andWhere($qb->expr()->eq('r.active', ':active')) - ->setParameter('active', true); + ->setParameter('event_type', $options['event_type']); } - - if ($options['group_by'] === null) { + + if (true === $options['active_only']) { + $options['query_builder']->andWhere($qb->expr()->eq('r.active', ':active')) + ->setParameter('active', true); + } + + if (null === $options['group_by']) { $builder->addEventListener( - FormEvents::PRE_SET_DATA, - function(FormEvent $event) use ($options) { - if ($options['event_type'] === null) { + FormEvents::PRE_SET_DATA, + function (FormEvent $event) use ($options) { + if (null === $options['event_type']) { $form = $event->getForm(); $name = $form->getName(); $config = $form->getConfig(); $type = $config->getType()->getName(); $options = $config->getOptions(); - $form->getParent()->add($name, $type, array_replace($options, array( - 'group_by' => function(Role $r) - { return $this->translatableStringHelper->localize($r->getType()->getName()); } - ))); + $form->getParent()->add($name, $type, array_replace($options, [ + 'group_by' => function (Role $r) { + return $this->translatableStringHelper->localize($r->getType()->getName()); + }, + ])); } - } - ); + } + ); } } - + public function configureOptions(OptionsResolver $resolver) { // create copy for use in Closure $translatableStringHelper = $this->translatableStringHelper; $translator = $this->translator; - + $resolver // add option "event_type" ->setDefined('event_type') - ->setAllowedTypes('event_type', array('null', EventType::class)) + ->setAllowedTypes('event_type', ['null', EventType::class]) ->setDefault('event_type', null) // add option allow unactive ->setDefault('active_only', true) - ->setAllowedTypes('active_only', array('boolean')) - ; - + ->setAllowedTypes('active_only', ['boolean']); + $qb = $this->roleRepository->createQueryBuilder('r'); - - $resolver->setDefaults(array( - 'class' => Role::class, - 'query_builder' => $qb, - 'group_by' => null, - 'choice_attr' => function(Role $r) { - return array( - 'data-event-type' => $r->getType()->getId(), - 'data-link-category' => $r->getType()->getId() - ); - }, - 'choice_label' => function(Role $r) - use ($translatableStringHelper, $translator) { - return $translatableStringHelper->localize($r->getName()). + + $resolver->setDefaults([ + 'class' => Role::class, + 'query_builder' => $qb, + 'group_by' => null, + 'choice_attr' => function (Role $r) { + return [ + 'data-event-type' => $r->getType()->getId(), + 'data-link-category' => $r->getType()->getId(), + ]; + }, + 'choice_label' => function (Role $r) use ($translatableStringHelper, $translator) { + return $translatableStringHelper->localize($r->getName()) . ($r->getActive() === true ? '' : - ' ('.$translator->trans('unactive').')'); - } - )); + ' (' . $translator->trans('unactive') . ')'); + }, + ]); } - + public function getParent() { return EntityType::class; diff --git a/src/Bundle/ChillEventBundle/Form/Type/PickStatusType.php b/src/Bundle/ChillEventBundle/Form/Type/PickStatusType.php index b4f40b7be..f554943b2 100644 --- a/src/Bundle/ChillEventBundle/Form/Type/PickStatusType.php +++ b/src/Bundle/ChillEventBundle/Form/Type/PickStatusType.php @@ -1,152 +1,129 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Form\Type; +use Chill\EventBundle\Entity\EventType; +use Chill\EventBundle\Entity\Status; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\EventBundle\Entity\Status; -use Chill\EventBundle\Entity\EventType; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Doctrine\ORM\EntityRepository; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Translation\TranslatorInterface; /** - * Allow to pick amongst type - * - * parameters : - * + * Allow to pick amongst type. + * + * parameters : + * * - event_type : restricts to a certain event type. Default null (= all event types) * - active_only: restricts to active type only. Default true - * - * @author Julien Fastré - * @author Champs Libres */ class PickStatusType extends AbstractType { - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var EntityRepository */ protected $statusRepository; - + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * @var TranslatorInterface + */ + protected $translator; + public function __construct( - TranslatableStringHelper $translatableStringHelper, - TranslatorInterface $translator, - EntityRepository $statusRepository + TranslatableStringHelper $translatableStringHelper, + TranslatorInterface $translator, + EntityRepository $statusRepository ) { $this->translatableStringHelper = $translatableStringHelper; $this->translator = $translator; $this->statusRepository = $statusRepository; } - + public function buildForm(FormBuilderInterface $builder, array $options) { $qb = $options['query_builder']; - + if ($options['event_type'] instanceof EventType) { $options['query_builder']->where($qb->expr()->eq('r.type', ':event_type')) - ->setParameter('event_type', $options['event_type']); - + ->setParameter('event_type', $options['event_type']); } - if ($options['active_only'] === true) { + if (true === $options['active_only']) { $options['query_builder']->andWhere($qb->expr()->eq('r.active', ':active')) - ->setParameter('active', true); + ->setParameter('active', true); } - - if ($options['group_by'] === null && $options['event_type'] === null) { + + if (null === $options['group_by'] && null === $options['event_type']) { $builder->addEventListener( - FormEvents::PRE_SET_DATA, - function(FormEvent $event) { - $form = $event->getForm(); - $name = $form->getName(); - $config = $form->getConfig(); - $type = $config->getType()->getName(); - $options = $config->getOptions(); - $form->getParent()->add($name, $type, array_replace($options, array( - 'group_by' => function(Status $s) - { return $this->translatableStringHelper->localize($s->getType()->getName()); } - ))); - } + FormEvents::PRE_SET_DATA, + function (FormEvent $event) { + $form = $event->getForm(); + $name = $form->getName(); + $config = $form->getConfig(); + $type = $config->getType()->getName(); + $options = $config->getOptions(); + $form->getParent()->add($name, $type, array_replace($options, [ + 'group_by' => function (Status $s) { + return $this->translatableStringHelper->localize($s->getType()->getName()); + }, + ])); + } ); } - } - + public function configureOptions(OptionsResolver $resolver) { // create copy for use in Closure $translatableStringHelper = $this->translatableStringHelper; $translator = $this->translator; - + $resolver // add option "event_type" ->setDefined('event_type') - ->setAllowedTypes('event_type', array('null', EventType::class)) + ->setAllowedTypes('event_type', ['null', EventType::class]) ->setDefault('event_type', null) // add option allow unactive ->setDefault('active_only', true) - ->setAllowedTypes('active_only', array('boolean')) - ; - + ->setAllowedTypes('active_only', ['boolean']); + $qb = $this->statusRepository->createQueryBuilder('r'); - - $resolver->setDefaults(array( - 'class' => Status::class, - 'query_builder' => $qb, - 'group_by' => null, - 'choice_attr' => function(Status $s) { - return array( - 'data-event-type' => $s->getType()->getId(), - 'data-link-category' => $s->getType()->getId() - ); - }, - 'choice_label' => function(Status $s) - use ($translatableStringHelper, $translator) { - return $translatableStringHelper->localize($s->getName()). + + $resolver->setDefaults([ + 'class' => Status::class, + 'query_builder' => $qb, + 'group_by' => null, + 'choice_attr' => function (Status $s) { + return [ + 'data-event-type' => $s->getType()->getId(), + 'data-link-category' => $s->getType()->getId(), + ]; + }, + 'choice_label' => function (Status $s) use ($translatableStringHelper, $translator) { + return $translatableStringHelper->localize($s->getName()) . ($s->getActive() === true ? '' : - ' ('.$translator->trans('unactive').')'); - } - )); + ' (' . $translator->trans('unactive') . ')'); + }, + ]); } - + public function getParent() { return EntityType::class; diff --git a/src/Bundle/ChillEventBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillEventBundle/Menu/PersonMenuBuilder.php index 0133409b8..c9f5f96b4 100644 --- a/src/Bundle/ChillEventBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillEventBundle/Menu/PersonMenuBuilder.php @@ -1,28 +1,32 @@ authorizationChecker = $authorizationChecker; $this->translator = $translator; } - - + public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ - $person = $parameters['person'] ?? null; - + $person = $parameters['person'] ?? null; + if ($this->authorizationChecker->isGranted(EventVoter::SEE, $person)) { - $menu->addChild($this->translator->trans('Events participation'), [ 'route' => 'chill_event__list_by_person', 'routeParameters' => [ - 'person_id' => $person->getId() - ] + 'person_id' => $person->getId(), + ], ]) - ->setExtras([ - 'order' => 500 - ]); + ->setExtras([ + 'order' => 500, + ]); } } - + public static function getMenuIds(): array { - return [ 'person' ]; + return ['person']; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillEventBundle/Repository/EventRepository.php b/src/Bundle/ChillEventBundle/Repository/EventRepository.php index a18e664ba..282902de0 100644 --- a/src/Bundle/ChillEventBundle/Repository/EventRepository.php +++ b/src/Bundle/ChillEventBundle/Repository/EventRepository.php @@ -1,22 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Repository; @@ -24,12 +12,8 @@ namespace Chill\EventBundle\Repository; use Doctrine\ORM\EntityRepository; /** - * Class EventRepository - * - * @package Chill\EventBundle\Repository - * @author Mathieu Jaumotte jaum_mathieu@collectifs.net + * Class EventRepository. */ class EventRepository extends EntityRepository { - } diff --git a/src/Bundle/ChillEventBundle/Repository/ParticipationRepository.php b/src/Bundle/ChillEventBundle/Repository/ParticipationRepository.php index 29bd09e9a..75dc4d346 100644 --- a/src/Bundle/ChillEventBundle/Repository/ParticipationRepository.php +++ b/src/Bundle/ChillEventBundle/Repository/ParticipationRepository.php @@ -1,22 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Repository; @@ -24,20 +12,18 @@ namespace Chill\EventBundle\Repository; use Doctrine\ORM\EntityRepository; /** - * Class ParticipationRepository - * - * @package Chill\EventBundle\Repository - * @author Mathieu Jaumotte jaum_mathieu@collectifs.net + * Class ParticipationRepository. */ class ParticipationRepository extends EntityRepository { - /** - * Count number of participations per person + * Count number of participations per person. * * @param $person_id - * @return mixed + * * @throws \Doctrine\ORM\NonUniqueResultException + * + * @return mixed */ public function countByPerson($person_id) { @@ -46,18 +32,17 @@ class ParticipationRepository extends EntityRepository ->where('p.id = :person_id') ->setParameter(':person_id', $person_id) ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } - - + /** - * Return paginated participations for a person and in reachables circles + * Return paginated participations for a person and in reachables circles. * * @param $person_id * @param $reachablesCircles * @param $first * @param $max + * * @return mixed */ public function findByPersonInCircle($person_id, $reachablesCircles, $first, $max) @@ -67,17 +52,13 @@ class ParticipationRepository extends EntityRepository ->where('p.person = :person_id') ->andWhere('e.circle IN (:reachable_circles)') ->orderBy('e.date', 'ASC') - ->setParameters(array( + ->setParameters([ ':person_id' => $person_id, - ':reachable_circles' => $reachablesCircles - )) + ':reachable_circles' => $reachablesCircles, + ]) ->setFirstResult($first) ->setMaxResults($max) ->getQuery() - ->getResult() - ; + ->getResult(); } - - - } diff --git a/src/Bundle/ChillEventBundle/Resources/test/Fixtures/App/AppKernel.php b/src/Bundle/ChillEventBundle/Resources/test/Fixtures/App/AppKernel.php index 366c1e6a0..59f7702f7 100644 --- a/src/Bundle/ChillEventBundle/Resources/test/Fixtures/App/AppKernel.php +++ b/src/Bundle/ChillEventBundle/Resources/test/Fixtures/App/AppKernel.php @@ -1,13 +1,36 @@ -load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - } - - /** - * @return string - */ - public function getCacheDir() - { - return sys_get_temp_dir().'/ChillEventBundle/cache'; - } - - /** - * @return string - */ - public function getLogDir() - { - return sys_get_temp_dir().'/ChillEventBundle/logs'; - } + { + $loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml'); + } } diff --git a/src/Bundle/ChillEventBundle/Resources/test/bootstrap.php b/src/Bundle/ChillEventBundle/Resources/test/bootstrap.php index 0279b4ee6..1260ef94b 100644 --- a/src/Bundle/ChillEventBundle/Resources/test/bootstrap.php +++ b/src/Bundle/ChillEventBundle/Resources/test/bootstrap.php @@ -1,8 +1,14 @@ - * @author Champs Libres */ class EventSearch extends AbstractSearch { - + public const NAME = 'event_regular'; + /** - * * @var EntityRepository */ private $er; - + /** - * - * @var \Chill\MainBundle\Entity\User - */ - private $user; - - /** - * * @var AuthorizationHelper */ private $helper; - + /** - * - * @var TemplatingEngine - */ - private $templating; - - /** - * * @var PaginatorFactory */ private $paginationFactory; - - const NAME = 'event_regular'; - + + /** + * @var TemplatingEngine + */ + private $templating; + + /** + * @var \Chill\MainBundle\Entity\User + */ + private $user; + public function __construct( - TokenStorageInterface $tokenStorage, - EntityRepository $eventRepository, - AuthorizationHelper $authorizationHelper, - TemplatingEngine $templating, - PaginatorFactory $paginatorFactory - ) - { + TokenStorageInterface $tokenStorage, + EntityRepository $eventRepository, + AuthorizationHelper $authorizationHelper, + TemplatingEngine $templating, + PaginatorFactory $paginatorFactory + ) { $this->user = $tokenStorage->getToken()->getUser(); $this->er = $eventRepository; $this->helper = $authorizationHelper; $this->templating = $templating; $this->paginationFactory = $paginatorFactory; } - - public function supports($domain, $format) - { - return 'event' === $domain or 'events' === $domain; - } - - public function isActiveByDefault() - { - return true; - } - + public function getOrder() { return 3000; } - public function renderResult(array $terms, $start = 0, $limit = 50, - array $options = array(), $format = 'html') + public function isActiveByDefault() { + return true; + } + + public function renderResult( + array $terms, + $start = 0, + $limit = 50, + array $options = [], + $format = 'html' + ) { $total = $this->count($terms); $paginator = $this->paginationFactory->create($total); - - if ($format === 'html') { - return $this->templating->render('ChillEventBundle:Event:list.html.twig', - array( + + if ('html' === $format) { + return $this->templating->render( + 'ChillEventBundle:Event:list.html.twig', + [ 'events' => $this->search($terms, $start, $limit, $options), 'pattern' => $this->recomposePattern($terms, $this->getAvailableTerms(), $terms['_domain']), 'total' => $total, 'start' => $start, 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], 'paginator' => $paginator, - 'search_name' => self::NAME - )); + 'search_name' => self::NAME, + ] + ); } - else if ($format === 'json') { + + if ('json' === $format) { $results = []; $search = $this->search($terms, $start, $limit, $options); + foreach ($search as $item) { $results[] = [ 'id' => $item->getId(), 'text' => $item->getDate()->format('d/m/Y, H:i') . ' → ' . // $item->getType()->getName()['fr'] . ': ' . // display the type of event - $item->getName() + $item->getName(), ]; } + return [ 'results' => $results, 'pagination' => [ - 'more' => $paginator->hasNextPage() - ] + 'more' => $paginator->hasNextPage(), + ], ]; } } - - protected function getAvailableTerms() + + public function supports($domain, $format) { - return array('date-from', 'date-to', 'name', 'date'); + return 'event' === $domain or 'events' === $domain; } - - protected function search(array $terms, $start, $limit, $options) - { - $qb = $this->er->createQueryBuilder('e'); - $qb->select('e'); - $this->composeQuery($qb, $terms) - ->setMaxResults($limit) - ->setFirstResult($start) - ->orderBy('e.date', 'DESC') - ; - - return $qb->getQuery()->getResult(); - } - - protected function count(array $terms) - { - $qb = $this->er->createQueryBuilder('e'); - $qb->select('COUNT(e)'); - $this->composeQuery($qb, $terms) - ; - - return $qb->getQuery()->getSingleScalarResult(); - } - + protected function composeQuery(QueryBuilder &$qb, $terms) { - // add security clauses $reachableCenters = $this->helper - ->getReachableCenters($this->user, new Role('CHILL_EVENT_SEE')); - + ->getReachableCenters($this->user, new Role('CHILL_EVENT_SEE')); + if (count($reachableCenters) === 0) { // add a clause to block all events $where = $qb->expr()->isNull('e.center'); $qb->andWhere($where); } else { - $n = 0; $orWhere = $qb->expr()->orX(); + foreach ($reachableCenters as $center) { - $circles = $this->helper->getReachableScopes($this->user, - new Role('CHILL_EVENT_SEE'), $center); + $circles = $this->helper->getReachableScopes( + $this->user, + new Role('CHILL_EVENT_SEE'), + $center + ); $where = $qb->expr()->andX( - $qb->expr()->eq('e.center', ':center_'.$n), - $qb->expr()->in('e.circle', ':circle_'.$n) - ); - $qb->setParameter('center_'.$n, $center); - $qb->setParameter('circle_'.$n, $circles); + $qb->expr()->eq('e.center', ':center_' . $n), + $qb->expr()->in('e.circle', ':circle_' . $n) + ); + $qb->setParameter('center_' . $n, $center); + $qb->setParameter('circle_' . $n, $circles); $orWhere->add($where); } - + $qb->andWhere($orWhere); } - + if ( - (isset($terms['name']) OR isset($terms['_default'])) - AND - (!empty($terms['name']) OR !empty($terms['_default']))) { + (isset($terms['name']) or isset($terms['_default'])) + and (!empty($terms['name']) or !empty($terms['_default'])) + ) { // the form with name:"xyz" has precedence - $name = isset($terms['name']) ? $terms['name'] : $terms['_default']; - + $name = $terms['name'] ?? $terms['_default']; + $where = $qb->expr()->like('UNACCENT(LOWER(e.name))', ':name'); - $qb->setParameter('name', '%'.$name.'%'); + $qb->setParameter('name', '%' . $name . '%'); $qb->andWhere($where); } - + if (isset($terms['date'])) { $date = $this->parseDate($terms['date']); - + $where = $qb->expr()->eq('e.date', ':date'); $qb->setParameter('date', $date); $qb->andWhere($where); } - + if (isset($terms['date-from'])) { $date = $this->parseDate($terms['date-from']); - + $where = $qb->expr()->gte('e.date', ':datefrom'); $qb->setParameter('datefrom', $date); $qb->andWhere($where); } - + if (isset($terms['date-to'])) { $date = $this->parseDate($terms['date-to']); - + $where = $qb->expr()->lte('e.date', ':dateto'); $qb->setParameter('dateto', $date); $qb->andWhere($where); } - + return $qb; } + + protected function count(array $terms) + { + $qb = $this->er->createQueryBuilder('e'); + $qb->select('COUNT(e)'); + $this->composeQuery($qb, $terms); + + return $qb->getQuery()->getSingleScalarResult(); + } + + protected function getAvailableTerms() + { + return ['date-from', 'date-to', 'name', 'date']; + } + + protected function search(array $terms, $start, $limit, $options) + { + $qb = $this->er->createQueryBuilder('e'); + $qb->select('e'); + $this->composeQuery($qb, $terms) + ->setMaxResults($limit) + ->setFirstResult($start) + ->orderBy('e.date', 'DESC'); + + return $qb->getQuery()->getResult(); + } } diff --git a/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php b/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php index c62767fa9..3ddc8f375 100644 --- a/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php +++ b/src/Bundle/ChillEventBundle/Security/Authorization/EventVoter.php @@ -1,143 +1,80 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Security\Authorization; -use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\EventBundle\Entity\Event; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Role\Role; -use Psr\Log\LoggerInterface; /** - * Description of EventVoter - * - * @author Mathieu Jaumotte - * @author Champs Libres + * Description of EventVoter. */ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const SEE = 'CHILL_EVENT_SEE'; - const SEE_DETAILS = 'CHILL_EVENT_SEE_DETAILS'; - const CREATE = 'CHILL_EVENT_CREATE'; - const UPDATE = 'CHILL_EVENT_UPDATE'; - - const ROLES = [ + public const CREATE = 'CHILL_EVENT_CREATE'; + + public const ROLES = [ self::SEE, self::SEE_DETAILS, self::CREATE, - self::UPDATE + self::UPDATE, ]; - - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; - + + public const SEE = 'CHILL_EVENT_SEE'; + + public const SEE_DETAILS = 'CHILL_EVENT_SEE_DETAILS'; + + public const UPDATE = 'CHILL_EVENT_UPDATE'; + /** * @var AccessDecisionManagerInterface */ protected $accessDecisionManager; - + + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; + /** * @var LoggerInterface */ protected $logger; - + public function __construct( AccessDecisionManagerInterface $accessDecisionManager, AuthorizationHelper $authorizationHelper, LoggerInterface $logger - ) - { + ) { $this->accessDecisionManager = $accessDecisionManager; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; } - - public function supports($attribute, $subject) - { - return ($subject instanceof Event && in_array($attribute, self::ROLES)) - || - ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SEE ])) - || - (NULL === $subject && $attribute === self::SEE ) - ; - } - - /** - * - * @param string $attribute - * @param Event $subject - * @param TokenInterface $token - * @return boolean - */ - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) - { - $this->logger->debug(sprintf("Voting from %s class", self::class)); - - if (!$token->getUser() instanceof User) { - return false; - } - - if ($subject instanceof Event) { - return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } elseif ($subject instanceof Person) { - return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } else { - - // subject is null. We check that at least one center is reachable - $centers = $this->authorizationHelper - ->getReachableCenters($token->getUser(), new Role($attribute)); - - return count($centers) > 0; - } - - if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { - return false; - } - - return $this->authorizationHelper->userHasAccess( - $token->getUser(), - $subject, - $attribute - ); - } - - public function getRoles() { return self::ROLES; } - + public function getRolesWithHierarchy() { return [ - 'Event' => self::ROLES + 'Event' => self::ROLES, ]; } @@ -145,5 +82,50 @@ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInter { return []; } - + + public function supports($attribute, $subject) + { + return ($subject instanceof Event && in_array($attribute, self::ROLES)) + || ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE])) + || (null === $subject && self::SEE === $attribute); + } + + /** + * @param string $attribute + * @param Event $subject + * + * @return bool + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $this->logger->debug(sprintf('Voting from %s class', self::class)); + + if (!$token->getUser() instanceof User) { + return false; + } + + if ($subject instanceof Event) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + } + + if ($subject instanceof Person) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + } + + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper + ->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; + + if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { + return false; + } + + return $this->authorizationHelper->userHasAccess( + $token->getUser(), + $subject, + $attribute + ); + } } diff --git a/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php b/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php index 50e05e279..f00019c28 100644 --- a/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php +++ b/src/Bundle/ChillEventBundle/Security/Authorization/ParticipationVoter.php @@ -1,64 +1,53 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Security\Authorization; -use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\EventBundle\Entity\Participation; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Role\Role; use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const SEE = 'CHILL_EVENT_PARTICIPATION_SEE'; - const SEE_DETAILS = 'CHILL_EVENT_PARTICIPATION_SEE_DETAILS'; - const CREATE = 'CHILL_EVENT_PARTICIPATION_CREATE'; - const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE'; + public const CREATE = 'CHILL_EVENT_PARTICIPATION_CREATE'; - const ROLES = [ + public const ROLES = [ self::SEE, self::SEE_DETAILS, self::CREATE, - self::UPDATE + self::UPDATE, ]; - /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; + public const SEE = 'CHILL_EVENT_PARTICIPATION_SEE'; + + public const SEE_DETAILS = 'CHILL_EVENT_PARTICIPATION_SEE_DETAILS'; + + public const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE'; /** * @var AccessDecisionManagerInterface */ protected $accessDecisionManager; + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; + /** * @var LoggerInterface */ @@ -68,65 +57,12 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar AccessDecisionManagerInterface $accessDecisionManager, AuthorizationHelper $authorizationHelper, LoggerInterface $logger - ) - { + ) { $this->accessDecisionManager = $accessDecisionManager; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; } - public function supports($attribute, $subject) - { - return ($subject instanceof Participation && in_array($attribute, self::ROLES)) - || - ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SEE ])) - || - (NULL === $subject && $attribute === self::SEE ) - ; - } - - /** - * - * @param string $attribute - * @param Participation $subject - * @param TokenInterface $token - * @return boolean - */ - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) - { - $this->logger->debug(sprintf("Voting from %s class", self::class)); - - if (!$token->getUser() instanceof User) { - return false; - } - - if ($subject instanceof Participation) { - return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } elseif ($subject instanceof Person) { - return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); - - } else { - - // subject is null. We check that at least one center is reachable - $centers = $this->authorizationHelper - ->getReachableCenters($token->getUser(), new Role($attribute)); - - return count($centers) > 0; - } - - if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { - return false; - } - - return $this->authorizationHelper->userHasAccess( - $token->getUser(), - $subject, - $attribute - ); - - } - public function getRoles() { return self::ROLES; @@ -135,7 +71,7 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar public function getRolesWithHierarchy() { return [ - 'Event' => self::ROLES + 'Event' => self::ROLES, ]; } @@ -144,4 +80,49 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar return []; } + public function supports($attribute, $subject) + { + return ($subject instanceof Participation && in_array($attribute, self::ROLES)) + || ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE])) + || (null === $subject && self::SEE === $attribute); + } + + /** + * @param string $attribute + * @param Participation $subject + * + * @return bool + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $this->logger->debug(sprintf('Voting from %s class', self::class)); + + if (!$token->getUser() instanceof User) { + return false; + } + + if ($subject instanceof Participation) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + } + + if ($subject instanceof Person) { + return $this->authorizationHelper->userHasAccess($token->getUser(), $subject, $attribute); + } + + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper + ->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; + + if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { + return false; + } + + return $this->authorizationHelper->userHasAccess( + $token->getUser(), + $subject, + $attribute + ); + } } diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/EventControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/EventControllerTest.php index d955d4a56..113fffa99 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/EventControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/EventControllerTest.php @@ -1,16 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -56,5 +67,5 @@ class EventControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/EventTypeControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/EventTypeControllerTest.php index 57af95de5..85347ba8e 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/EventTypeControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/EventTypeControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class EventTypeControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php index a51fae197..f03b5a5ba 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/ParticipationControllerTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Tests\Controller; @@ -22,263 +12,220 @@ namespace Chill\EventBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the creation of participation controller - * + * Test the creation of participation controller. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ParticipationControllerTest extends WebTestCase { /** - * * @var \Symfony\Component\BrowserKit\Client */ protected $client; - + /** - * * @var \Doctrine\ORM\EntityManagerInterface */ protected $em; - + /** * Keep a cache for each person id given by the function getRandomPerson. - * + * * You may ask to ignore some people by adding their id to the array. - * + * * This is reset by setUp(). * - * @var int[] + * @var int[] */ - private $personsIdsCache = array(); - + private $personsIdsCache = []; + public function setUp() { self::bootKernel(); - - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); - + + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); + $container = self::$kernel->getContainer(); - - $this->em = $container->get('doctrine.orm.entity_manager') - ; - - $this->personsIdsCache = array(); + + $this->em = $container->get('doctrine.orm.entity_manager'); + + $this->personsIdsCache = []; } - - /** - * - * - * @return \Chill\EventBundle\Entity\Event - */ - protected function getRandomEvent($centerName = 'Center A', $circleName = 'social') - { - $center = $this->em->getRepository('ChillMainBundle:Center') - ->findByName($centerName); - - $circles = $this->em->getRepository('ChillMainBundle:Scope') - ->findAll(); - array_filter($circles, function($circle) use ($circleName) { - return in_array($circleName, $circle->getName()); - }); - $circle = $circles[0]; - - $events = $this->em->getRepository('ChillEventBundle:Event') - ->findBy(array('center' => $center, 'circle' => $circle)); - - return $events[array_rand($events)]; - } - - /** - * Return a random event only if he has more than one participation. - * - * @param string $centerName - * @param type $circleName - * @return \Chill\EventBundle\Entity\Event - */ - protected function getRandomEventWithMultipleParticipations( - $centerName = 'Center A', - $circleName = 'social') - { - $event = $this->getRandomEvent($centerName, $circleName); - - return $event->getParticipations()->count() > 1 ? - $event : - $this->getRandomEventWithMultipleParticipations($centerName, $circleName); - } - - /** - * Returns a person randomly. - * - * This function does not give the same person twice - * for each test. - * - * You may ask to ignore some people by adding their id to the property - * `$this->personsIdsCache` - * - * @param string $centerName - * @return \Chill\PersonBundle\Entity\Person - */ - protected function getRandomPerson($centerName = 'Center A') - { - $center = $this->em->getRepository('ChillMainBundle:Center') - ->findByName($centerName); - - $persons = $this->em->getRepository('ChillPersonBundle:Person') - ->findBy(array('center' => $center)); - - $person = $persons[array_rand($persons)]; - - if (in_array($person->getId(), $this->personsIdsCache)) { - return $this->getRandomPerson($centerName); // we try another time - } else { - $this->personsIdsCache[] = $person->getId(); - return $person; - } - - } - - public function testNewActionWrongParameters() - { - $event = $this->getRandomEvent(); - $person = $this->getRandomPerson(); - - // missing person_id or persons_ids - $this->client->request('GET', '/fr/event/participation/new', - array( - 'event_id' => $event->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/new fail if " - . "both person_id and persons_ids are missing"); - - // having both person_id and persons_ids - $this->client->request('GET', '/fr/event/participation/new', - array( - 'event_id' => $event->getId(), - 'persons_ids' => implode(',', array( - $this->getRandomPerson()->getId(), - $this->getRandomPerson()->getId() - )), - 'person_id' => $person->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/new fail if both person_id and " - . "persons_ids are set"); - - // missing event_id - $this->client->request('GET', '/fr/event/participation/new', - array( - 'person_id' => $person->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/new fails if event_id is missing"); - - // persons_ids with wrong content - $this->client->request('GET', '/fr/event/participation/new', - array( - 'persons_ids' => 'a,b,531', - 'event_id' => $event->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/new fails if persons_ids has wrong content"); - } - + /** * This method test participation creation with wrong parameters. - * + * * Those request should fail before any processing. */ public function testCreateActionWrongParameters() { $event = $this->getRandomEvent(); $person = $this->getRandomPerson(); - + // missing person_id or persons_ids - $this->client->request('GET', '/fr/event/participation/create', - array( - 'event_id' => $event->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/create fail if " - . "both person_id and persons_ids are missing"); - + $this->client->request( + 'GET', + '/fr/event/participation/create', + [ + 'event_id' => $event->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/create fail if ' + . 'both person_id and persons_ids are missing' + ); + // having both person_id and persons_ids - $this->client->request('GET', '/fr/event/participation/create', - array( - 'event_id' => $event->getId(), - 'persons_ids' => implode(',', array( - $this->getRandomPerson()->getId(), - $this->getRandomPerson()->getId() - )), - 'person_id' => $person->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/create fail if both person_id and " - . "persons_ids are set"); - + $this->client->request( + 'GET', + '/fr/event/participation/create', + [ + 'event_id' => $event->getId(), + 'persons_ids' => implode(',', [ + $this->getRandomPerson()->getId(), + $this->getRandomPerson()->getId(), + ]), + 'person_id' => $person->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/create fail if both person_id and ' + . 'persons_ids are set' + ); + // missing event_id - $this->client->request('GET', '/fr/event/participation/create', - array( - 'person_id' => $person->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/create fails if event_id is missing"); - + $this->client->request( + 'GET', + '/fr/event/participation/create', + [ + 'person_id' => $person->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/create fails if event_id is missing' + ); + // persons_ids with wrong content - $this->client->request('GET', '/fr/event/participation/create', - array( - 'persons_ids' => 'a,b,531', - 'event_id' => $event->getId() - )); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test that /fr/event/participation/create fails if persons_ids has wrong content"); + $this->client->request( + 'GET', + '/fr/event/participation/create', + [ + 'persons_ids' => 'a,b,531', + 'event_id' => $event->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/create fails if persons_ids has wrong content' + ); } - - public function testNewSingleAction() + + public function testEditMultipleAction() + { + /* @var $event \Chill\EventBundle\Entity\Event */ + $event = $this->getRandomEventWithMultipleParticipations(); + + $crawler = $this->client->request('GET', '/fr/event/participation/' . $event->getId() . + '/edit_multiple'); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $button = $crawler->selectButton('Mettre à jour'); + $this->assertEquals(1, $button->count(), "test the form with button 'mettre à jour' exists "); + + $this->client->submit($button->form(), [ + 'form[participations][0][role]' => $event->getType()->getRoles()->first()->getId(), + 'form[participations][0][status]' => $event->getType()->getStatuses()->first()->getId(), + 'form[participations][1][role]' => $event->getType()->getRoles()->last()->getId(), + 'form[participations][1][status]' => $event->getType()->getStatuses()->last()->getId(), + ]); + + $this->assertTrue($this->client->getResponse() + ->isRedirect('/fr/event/event/' . $event->getId() . '/show')); + } + + public function testNewActionWrongParameters() { $event = $this->getRandomEvent(); - // record the number of participation for the event - $nbParticipations = $event->getParticipations()->count(); $person = $this->getRandomPerson(); - - $crawler = $this->client->request('GET', '/fr/event/participation/new', - array( - 'person_id' => $person->getId(), - 'event_id' => $event->getId() - )); - $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/new is successful"); - - $button = $crawler->selectButton('Créer'); - - $this->assertNotNull($button, "test the form with button 'Créer' exists"); - - $this->client->submit($button->form(), array( - 'participation[role]' => $event->getType()->getRoles()->first()->getId(), - 'participation[status]' => $event->getType()->getStatuses()->first()->getId() - )); - - $this->assertTrue($this->client->getResponse()->isRedirect()); - $crawler = $this->client->followRedirect(); - - $span = $crawler->filter('table td span.entity-person a:contains("' - .$person->getFirstName().'"):contains("'.$person->getLastname().'")'); - - $this->assertGreaterThan(0, count($span)); - - // as the container has reloaded, reload the event - $event = $this->em->getRepository('ChillEventBundle:Event')->find($event->getId()); - $this->em->refresh($event); - - $this->assertEquals($nbParticipations + 1, $event->getParticipations()->count()); + // missing person_id or persons_ids + $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'event_id' => $event->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/new fail if ' + . 'both person_id and persons_ids are missing' + ); + + // having both person_id and persons_ids + $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'event_id' => $event->getId(), + 'persons_ids' => implode(',', [ + $this->getRandomPerson()->getId(), + $this->getRandomPerson()->getId(), + ]), + 'person_id' => $person->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/new fail if both person_id and ' + . 'persons_ids are set' + ); + + // missing event_id + $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'person_id' => $person->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/new fails if event_id is missing' + ); + + // persons_ids with wrong content + $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'persons_ids' => 'a,b,531', + 'event_id' => $event->getId(), + ] + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test that /fr/event/participation/new fails if persons_ids has wrong content' + ); } - + public function testNewMultipleAction() { $event = $this->getRandomEvent(); @@ -286,79 +233,91 @@ class ParticipationControllerTest extends WebTestCase $nbParticipations = $event->getParticipations()->count(); // make ignore the people already in the event from the function getRandomPerson $this->personsIdsCache = array_merge( - $this->personsIdsCache, - $event->getParticipations()->map( - function($p) { return $p->getPerson()->getId(); } - ) - ->toArray() - ); + $this->personsIdsCache, + $event->getParticipations()->map( + function ($p) { return $p->getPerson()->getId(); } + ) + ->toArray() + ); // get some random people $person1 = $this->getRandomPerson(); $person2 = $this->getRandomPerson(); - - $crawler = $this->client->request('GET', '/fr/event/participation/new', - array( - 'persons_ids' => implode(',', array($person1->getId(), $person2->getId())), - 'event_id' => $event->getId() - )); - $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/new is successful"); - + $crawler = $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'persons_ids' => implode(',', [$person1->getId(), $person2->getId()]), + 'event_id' => $event->getId(), + ] + ); + + $this->assertEquals( + 200, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/new is successful' + ); + $button = $crawler->selectButton('Créer'); - + $this->assertNotNull($button, "test the form with button 'Créer' exists"); - - $this->client->submit($button->form(), array( - 'form' => array( - 'participations' => array( - 0 => array( + + $this->client->submit($button->form(), [ + 'form' => [ + 'participations' => [ + 0 => [ 'role' => $event->getType()->getRoles()->first()->getId(), - 'status' => $event->getType()->getStatuses()->first()->getId() - ), - 1 => array( + 'status' => $event->getType()->getStatuses()->first()->getId(), + ], + 1 => [ 'role' => $event->getType()->getRoles()->first()->getId(), - 'status' => $event->getType()->getStatuses()->first()->getId() - ), - ) - ) - )); - + 'status' => $event->getType()->getStatuses()->first()->getId(), + ], + ], + ], + ]); + $this->assertTrue($this->client->getResponse()->isRedirect()); $crawler = $this->client->followRedirect(); $span1 = $crawler->filter('table td span.entity-person a:contains("' - .$person1->getFirstName().'"):contains("'.$person1->getLastname().'")'); + . $person1->getFirstName() . '"):contains("' . $person1->getLastname() . '")'); $this->assertGreaterThan(0, count($span1)); $span2 = $crawler->filter('table td span.entity-person a:contains("' - .$person2->getFirstName().'"):contains("'.$person2->getLastname().'")'); + . $person2->getFirstName() . '"):contains("' . $person2->getLastname() . '")'); $this->assertGreaterThan(0, count($span2)); - + // as the container has reloaded, reload the event $event = $this->em->getRepository('ChillEventBundle:Event')->find($event->getId()); $this->em->refresh($event); - + $this->assertEquals($nbParticipations + 2, $event->getParticipations()->count()); } - + public function testNewMultipleWithAllPeopleParticipating() { $event = $this->getRandomEventWithMultipleParticipations(); - + $persons_id = implode(',', $event->getParticipations()->map( - function($p) { return $p->getPerson()->getId(); } - )->toArray()); - - $crawler = $this->client->request('GET', '/fr/event/participation/new', - array( - 'persons_ids' => $persons_id, - 'event_id' => $event->getId() - )); - - $this->assertEquals(302, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/new is redirecting"); + function ($p) { return $p->getPerson()->getId(); } + )->toArray()); + + $crawler = $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'persons_ids' => $persons_id, + 'event_id' => $event->getId(), + ] + ); + + $this->assertEquals( + 302, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/new is redirecting' + ); } - + public function testNewMultipleWithSomePeopleParticipating() { $event = $this->getRandomEventWithMultipleParticipations(); @@ -366,83 +325,193 @@ class ParticipationControllerTest extends WebTestCase $nbParticipations = $event->getParticipations()->count(); // get the persons_id participating on this event $persons_id = $event->getParticipations()->map( - function($p) { return $p->getPerson()->getId(); } - )->toArray(); + function ($p) { return $p->getPerson()->getId(); } + )->toArray(); // exclude the existing persons_ids from the new person $this->personsIdsCache = array_merge($this->personsIdsCache, $persons_id); - + // get a random person $newPerson = $this->getRandomPerson(); - + // build the `persons_ids` parameter - $persons_ids_string = implode(',', array_merge($persons_id, - array($newPerson->getId()))); - - $crawler = $this->client->request('GET', '/fr/event/participation/new', - array( - 'persons_ids' => $persons_ids_string, - 'event_id' => $event->getId() - )); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), - "test that /fr/event/participation/new is successful"); - + $persons_ids_string = implode(',', array_merge( + $persons_id, + [$newPerson->getId()] + )); + + $crawler = $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'persons_ids' => $persons_ids_string, + 'event_id' => $event->getId(), + ] + ); + + $this->assertEquals( + 200, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/new is successful' + ); + // count that the one UL contains the new person string $firstPerson = $event->getParticipations()->first()->getPerson(); - $ul = $crawler->filter('ul:contains("'.$firstPerson->getLastName().'")' - . ':contains("'.$firstPerson->getFirstName().'")'); - - $this->assertEquals(1, $ul->count(), - "assert an ul containing the name of ignored people is present"); - $this->assertEquals($event->getParticipations()->count(), $ul->children()->count(), - "assert the li listing ignored people has the correct number"); - + $ul = $crawler->filter('ul:contains("' . $firstPerson->getLastName() . '")' + . ':contains("' . $firstPerson->getFirstName() . '")'); + + $this->assertEquals( + 1, + $ul->count(), + 'assert an ul containing the name of ignored people is present' + ); + $this->assertEquals( + $event->getParticipations()->count(), + $ul->children()->count(), + 'assert the li listing ignored people has the correct number' + ); + // test a form is present on the page $button = $crawler->selectButton('Créer'); - + $this->assertNotNull($button, "test the form with button 'Créer' exists"); - + // submit the form - $this->client->submit($button->form(), array( + $this->client->submit($button->form(), [ 'participation[role]' => $event->getType()->getRoles()->first()->getId(), - 'participation[status]' => $event->getType()->getStatuses()->first()->getId() - )); - + 'participation[status]' => $event->getType()->getStatuses()->first()->getId(), + ]); + $this->assertTrue($this->client->getResponse()->isRedirect()); - + // reload the event and test there is a new participation $event = $this->em->getRepository('ChillEventBundle:Event') - ->find($event->getId()); + ->find($event->getId()); $this->em->refresh($event); - - $this->assertEquals($nbParticipations + 1, $event->getParticipations()->count(), - "Test we have persisted a new participation associated to the test"); + + $this->assertEquals( + $nbParticipations + 1, + $event->getParticipations()->count(), + 'Test we have persisted a new participation associated to the test' + ); } - - public function testEditMultipleAction() + + public function testNewSingleAction() { - /* @var $event \Chill\EventBundle\Entity\Event */ - $event = $this->getRandomEventWithMultipleParticipations(); - - $crawler = $this->client->request('GET', '/fr/event/participation/'.$event->getId(). - '/edit_multiple'); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - - $button = $crawler->selectButton('Mettre à jour'); - $this->assertEquals(1, $button->count(), "test the form with button 'mettre à jour' exists "); - - - $this->client->submit($button->form(), array( - 'form[participations][0][role]' => $event->getType()->getRoles()->first()->getId(), - 'form[participations][0][status]' => $event->getType()->getStatuses()->first()->getId(), - 'form[participations][1][role]' => $event->getType()->getRoles()->last()->getId(), - 'form[participations][1][status]' => $event->getType()->getStatuses()->last()->getId(), - )); - - $this->assertTrue($this->client->getResponse() - ->isRedirect('/fr/event/event/'.$event->getId().'/show')); + $event = $this->getRandomEvent(); + // record the number of participation for the event + $nbParticipations = $event->getParticipations()->count(); + $person = $this->getRandomPerson(); + + $crawler = $this->client->request( + 'GET', + '/fr/event/participation/new', + [ + 'person_id' => $person->getId(), + 'event_id' => $event->getId(), + ] + ); + + $this->assertEquals( + 200, + $this->client->getResponse()->getStatusCode(), + 'test that /fr/event/participation/new is successful' + ); + + $button = $crawler->selectButton('Créer'); + + $this->assertNotNull($button, "test the form with button 'Créer' exists"); + + $this->client->submit($button->form(), [ + 'participation[role]' => $event->getType()->getRoles()->first()->getId(), + 'participation[status]' => $event->getType()->getStatuses()->first()->getId(), + ]); + + $this->assertTrue($this->client->getResponse()->isRedirect()); + $crawler = $this->client->followRedirect(); + + $span = $crawler->filter('table td span.entity-person a:contains("' + . $person->getFirstName() . '"):contains("' . $person->getLastname() . '")'); + + $this->assertGreaterThan(0, count($span)); + + // as the container has reloaded, reload the event + $event = $this->em->getRepository('ChillEventBundle:Event')->find($event->getId()); + $this->em->refresh($event); + + $this->assertEquals($nbParticipations + 1, $event->getParticipations()->count()); + } + + /** + * @param mixed $centerName + * @param mixed $circleName + * + * @return \Chill\EventBundle\Entity\Event + */ + protected function getRandomEvent($centerName = 'Center A', $circleName = 'social') + { + $center = $this->em->getRepository('ChillMainBundle:Center') + ->findByName($centerName); + + $circles = $this->em->getRepository('ChillMainBundle:Scope') + ->findAll(); + array_filter($circles, function ($circle) use ($circleName) { + return in_array($circleName, $circle->getName()); + }); + $circle = $circles[0]; + + $events = $this->em->getRepository('ChillEventBundle:Event') + ->findBy(['center' => $center, 'circle' => $circle]); + + return $events[array_rand($events)]; + } + + /** + * Return a random event only if he has more than one participation. + * + * @param string $centerName + * @param type $circleName + * + * @return \Chill\EventBundle\Entity\Event + */ + protected function getRandomEventWithMultipleParticipations( + $centerName = 'Center A', + $circleName = 'social' + ) { + $event = $this->getRandomEvent($centerName, $circleName); + + return $event->getParticipations()->count() > 1 ? + $event : + $this->getRandomEventWithMultipleParticipations($centerName, $circleName); + } + + /** + * Returns a person randomly. + * + * This function does not give the same person twice + * for each test. + * + * You may ask to ignore some people by adding their id to the property + * `$this->personsIdsCache` + * + * @param string $centerName + * + * @return \Chill\PersonBundle\Entity\Person + */ + protected function getRandomPerson($centerName = 'Center A') + { + $center = $this->em->getRepository('ChillMainBundle:Center') + ->findByName($centerName); + + $persons = $this->em->getRepository('ChillPersonBundle:Person') + ->findBy(['center' => $center]); + + $person = $persons[array_rand($persons)]; + + if (in_array($person->getId(), $this->personsIdsCache)) { + return $this->getRandomPerson($centerName); // we try another time + } + $this->personsIdsCache[] = $person->getId(); + + return $person; } - - } diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/RoleControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/RoleControllerTest.php index f2286f208..23237d060 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/RoleControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/RoleControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class RoleControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillEventBundle/Tests/Controller/StatusControllerTest.php b/src/Bundle/ChillEventBundle/Tests/Controller/StatusControllerTest.php index 99e297575..2ddcabee2 100644 --- a/src/Bundle/ChillEventBundle/Tests/Controller/StatusControllerTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Controller/StatusControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class StatusControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillEventBundle/Tests/Search/EventSearchTest.php b/src/Bundle/ChillEventBundle/Tests/Search/EventSearchTest.php index bb31a7bfa..edb388cd7 100644 --- a/src/Bundle/ChillEventBundle/Tests/Search/EventSearchTest.php +++ b/src/Bundle/ChillEventBundle/Tests/Search/EventSearchTest.php @@ -1,398 +1,385 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Tests\Search; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\EventBundle\Entity\Event; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Chill\EventBundle\Search\EventSearch; - +use DateTime; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the EventSearch class + * Test the EventSearch class. * - * @author Julien Fastré + * @internal + * @coversNothing */ class EventSearchTest extends WebTestCase { /** - * The eventSearch service, which is used to search events + * The center A. + * + * @var \Chill\MainBundle\Entity\Center + */ + protected $centerA; + + /** + * @var \Symfony\Component\BrowserKit\Client + */ + protected $client; + + /** + * @var \Doctrine\ORM\EntityManagerInterface + */ + protected $entityManager; + + /** + * Events created during this test. + * + * @var Event[] + */ + protected $events = []; + + /** + * The eventSearch service, which is used to search events. * * @var \Chill\EventBundle\Search\EventSearch */ protected $eventSearch; - + /** - * - * @var \Doctrine\ORM\EntityManagerInterface - */ - protected $entityManager; - - /** - * The center A - * - * @var \Chill\MainBundle\Entity\Center - */ - protected $centerA; - - /** - * a random event type + * a random event type. * * @var \Chill\EventBundle\Entity\EventType */ protected $eventType; - + /** - * Events created during this test - * - * @var Event[] - */ - protected $events = array(); - - /** - * * @var \Prophecy\Prophet */ protected $prophet; - - /** - * - * @var \Symfony\Component\BrowserKit\Client - */ - protected $client; - + public function setUp() { self::bootKernel(); /* @var $kernel \Symfony\Component\HttpKernel\KernelInterface */ $kernel = self::$kernel; - - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); - - $this->prophet = new \Prophecy\Prophet; - + + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); + + $this->prophet = new \Prophecy\Prophet(); + $this->entityManager = self::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ; - + ->get('doctrine.orm.entity_manager'); + $this->centerA = $this->entityManager - ->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->getRepository('ChillMainBundle:Center') + ->findOneBy(['name' => 'Center A']); + $this->eventType = $this->entityManager - ->getRepository('ChillEventBundle:EventType') - ->findAll()[0]; - + ->getRepository('ChillEventBundle:EventType') + ->findAll()[0]; + $this->createEvents(); } - + public function tearDown() { foreach ($this->events as $event) { $this->entityManager->createQuery('DELETE FROM ChillEventBundle:Event e WHERE e.id = :event_id') - ->setParameter('event_id', $event->getId()) - ->execute(); + ->setParameter('event_id', $event->getId()) + ->execute(); } - - $this->events = array(); + + $this->events = []; } - + + public function testDisplayAll() + { + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events', + ]); + + $this->assertGreaterThanOrEqual( + 2, + $crawler->filter('table.events tr')->count(), + 'assert than more than 2 tr are present' + ); + } + + /** + * Test that a user connected with an user with the wrong center does not + * see the events. + */ + public function testDisplayAllWrongUser() + { + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center b_social', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@events printemps', + ]); + + $this->assertEquals( + 0, + $crawler->filter('tr:contains("Printemps")')->count(), + 'assert that the word "printemps" is present' + ); + } + + public function testSearchByDateDateBetween() + { + // serach with date from **and** date-to + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events date-from:2016-05-30 date-to:2016-06-20', + ]); + + /* @var $dateFrom \DateTime the date from in DateTime */ + $dateFrom = DateTime::createFromFormat('Y-m-d', '2016-05-30'); + $dateTo = DateTime::createFromFormat('Y-m-d', '2016-06-20'); + + $dates = $this->iterateOnRowsToFindDate($crawler->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + $this->assertLessThanOrEqual($dateTo, $date); + } + + // there should not have any other results, but if any other bundle + // add some other event, we go on next pages + + if ($crawler->selectLink('Voir tous les résultats')->count() == 0) { + return; + } + + // click on link "Voir tous les résultats" + $crawlerAllResults = $this->client->click($crawler + ->selectLink('Voir tous les résultats')->link()); + $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + $this->assertLessThanOrEqual($dateTo, $date); + } + + //iterate on pagination + $crawlerAllResults->filter('.pagination a')->each(function ($a, $i) use ($dateFrom) { + $page = $this->client->click($a->link()); + $dates = $this->iterateOnRowsToFindDate($page->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + $this->assertLessThanOrEqual($dateTo, $date); + } + }); + } + + public function testSearchByDateDateFromOnly() + { + // search with date from + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events date-from:2016-05-30', + ]); + /* @var $dateFrom \DateTime the date from in DateTime */ + $dateFrom = DateTime::createFromFormat('Y-m-d', '2016-05-30'); + + $dates = $this->iterateOnRowsToFindDate($crawler->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + } + + // click on link "Voir tous les résultats" + $crawlerAllResults = $this->client->click($crawler + ->selectLink('Voir tous les résultats')->link()); + $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + } + + //iterate on pagination + $crawlerAllResults->filter('.pagination a')->each(function ($a, $i) use ($dateFrom) { + $page = $this->client->click($a->link()); + $dates = $this->iterateOnRowsToFindDate($page->filter('tr')); + + foreach ($dates as $date) { + $this->assertGreaterThanOrEqual($dateFrom, $date); + } + }); + } + + public function testSearchByDateDateTo() + { + // serach with date from **and** date-to + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events date:2016-05-30', + ]); + + /* @var $dateFrom \DateTime the date from in DateTime */ + $dateTo = DateTime::createFromFormat('Y-m-d', '2016-05-30'); + + $dates = $this->iterateOnRowsToFindDate($crawler->filter('tr')); + + foreach ($dates as $date) { + $this->assertLessThanOrEqual($dateTo, $date); + } + + if ($crawler->selectLink('Voir tous les résultats')->count() == 0) { + return; + } + + // click on link "Voir tous les résultats" + $crawlerAllResults = $this->client->click($crawler + ->selectLink('Voir tous les résultats')->link()); + $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter('tr')); + + foreach ($dates as $date) { + $this->assertLessThanOrEqual($dateTo, $date); + } + + //iterate on pagination + $crawlerAllResults->filter('.pagination a')->each(function ($a, $i) { + $page = $this->client->click($a->link()); + $dates = $this->iterateOnRowsToFindDate($page->filter('tr')); + + foreach ($dates as $date) { + $this->assertLessThanOrEqual($dateTo, $date); + } + }); + } + + public function testSearchByDefault() + { + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events printemps', + ]); + + $this->assertEquals( + 1, + $crawler->filter('table.events tr')->count() - 1 /* as the header is a th */ , + 'assert than more than 2 tr are present' + ); + + $this->assertEquals( + 1, + $crawler->filter('tr:contains("Printemps")')->count(), + 'assert that the word "printemps" is present' + ); + } + + public function testSearchByName() + { + $crawler = $this->client->request('GET', '/fr/search', [ + 'q' => '@events name:printemps', + ]); + + $this->assertEquals( + 1, + $crawler->filter('table.events tr')->count() - 1 /* as the header is a th */ , + 'assert than more than 2 tr are present' + ); + + $this->assertEquals( + 1, + $crawler->filter('tr:contains("Printemps")')->count(), + 'assert that the word "printemps" is present' + ); + } + protected function createEvents() { $event1 = (new Event()) - ->setCenter($this->centerA) - ->setDate(new \DateTime('2016-05-30')) - ->setName('Printemps européen') - ->setType($this->eventType) - ->setCircle($this->getCircle()) - ; + ->setCenter($this->centerA) + ->setDate(new DateTime('2016-05-30')) + ->setName('Printemps européen') + ->setType($this->eventType) + ->setCircle($this->getCircle()); $this->entityManager->persist($event1); $this->events[] = $event1; - + $event2 = (new Event()) - ->setCenter($this->centerA) - ->setDate(new \DateTime('2016-06-24')) - ->setName('Hiver de la droite') - ->setType($this->eventType) - ->setCircle($this->getCircle()) - ; + ->setCenter($this->centerA) + ->setDate(new DateTime('2016-06-24')) + ->setName('Hiver de la droite') + ->setType($this->eventType) + ->setCircle($this->getCircle()); $this->entityManager->persist($event2); $this->events[] = $event2; - + $this->entityManager->flush(); } - + /** - * * @param string $name the name of the circle + * * @return \Chill\MainBundle\Entity\Scope */ protected function getCircle($name = 'social') { $circles = $this->entityManager->getRepository('ChillMainBundle:Scope') - ->findAll(); - + ->findAll(); + /* @var $circle \Chill\MainBundle\Entity\Scope */ - foreach($circles as $circle) { + foreach ($circles as $circle) { if (in_array($name, $circle->getName())) { return $circle; } } } - - public function testDisplayAll() - { - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events' - )); - - $this->assertGreaterThanOrEqual(2, $crawler->filter('table.events tr')->count(), - 'assert than more than 2 tr are present'); - } - - public function testSearchByDefault() - { - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events printemps' - )); - $this->assertEquals( - 1, - $crawler->filter('table.events tr')->count() - 1 /* as the header is a th */, - 'assert than more than 2 tr are present'); - - $this->assertEquals( - 1, - $crawler->filter('tr:contains("Printemps")')->count(), - 'assert that the word "printemps" is present'); - } - - public function testSearchByName() - { - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events name:printemps' - )); - - $this->assertEquals( - 1, - $crawler->filter('table.events tr')->count() - 1 /* as the header is a th */, - 'assert than more than 2 tr are present'); - - $this->assertEquals( - 1, - $crawler->filter('tr:contains("Printemps")')->count(), - 'assert that the word "printemps" is present'); - } - - public function testSearchByDateDateFromOnly() - { - // search with date from - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events date-from:2016-05-30' - )); - /* @var $dateFrom \DateTime the date from in DateTime */ - $dateFrom = \DateTime::createFromFormat("Y-m-d", "2016-05-30"); - - $dates = $this->iterateOnRowsToFindDate($crawler->filter("tr")); - - foreach($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - } - - // click on link "Voir tous les résultats" - $crawlerAllResults = $this->client->click($crawler - ->selectLink("Voir tous les résultats")->link()); - $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter("tr")); - - foreach ($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - } - - //iterate on pagination - $crawlerAllResults->filter(".pagination a")->each(function($a, $i) use ($dateFrom) { - $page = $this->client->click($a->link()); - $dates = $this->iterateOnRowsToFindDate($page->filter("tr")); - - foreach($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - } - }); - } - - public function testSearchByDateDateBetween() - { - // serach with date from **and** date-to - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events date-from:2016-05-30 date-to:2016-06-20' - )); - - /* @var $dateFrom \DateTime the date from in DateTime */ - $dateFrom = \DateTime::createFromFormat("Y-m-d", "2016-05-30"); - $dateTo = \DateTime::createFromFormat("Y-m-d", "2016-06-20"); - - $dates = $this->iterateOnRowsToFindDate($crawler->filter("tr")); - - foreach($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - $this->assertLessThanOrEqual($dateTo, $date); - } - - // there should not have any other results, but if any other bundle - // add some other event, we go on next pages - - if ($crawler->selectLink("Voir tous les résultats")->count() == 0) { - return ; - } - - // click on link "Voir tous les résultats" - $crawlerAllResults = $this->client->click($crawler - ->selectLink("Voir tous les résultats")->link()); - $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter("tr")); - - foreach ($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - $this->assertLessThanOrEqual($dateTo, $date); - } - - //iterate on pagination - $crawlerAllResults->filter(".pagination a")->each(function($a, $i) use ($dateFrom) { - $page = $this->client->click($a->link()); - $dates = $this->iterateOnRowsToFindDate($page->filter("tr")); - - foreach($dates as $date) { - $this->assertGreaterThanOrEqual($dateFrom, $date); - $this->assertLessThanOrEqual($dateTo, $date); - } - }); - } - - public function testSearchByDateDateTo() - { - - // serach with date from **and** date-to - $crawler = $this->client->request('GET', '/fr/search', array( - 'q' => '@events date:2016-05-30' - )); - - /* @var $dateFrom \DateTime the date from in DateTime */ - $dateTo = \DateTime::createFromFormat("Y-m-d", "2016-05-30"); - - $dates = $this->iterateOnRowsToFindDate($crawler->filter("tr")); - - foreach($dates as $date) { - $this->assertLessThanOrEqual($dateTo, $date); - } - - if ($crawler->selectLink("Voir tous les résultats")->count() == 0) { - return ; - } - - // click on link "Voir tous les résultats" - $crawlerAllResults = $this->client->click($crawler - ->selectLink("Voir tous les résultats")->link()); - $dates = $this->iterateOnRowsToFindDate($crawlerAllResults->filter("tr")); - - foreach ($dates as $date) { - $this->assertLessThanOrEqual($dateTo, $date); - } - - //iterate on pagination - $crawlerAllResults->filter(".pagination a")->each(function($a, $i) use ($dateFrom) { - $page = $this->client->click($a->link()); - $dates = $this->iterateOnRowsToFindDate($page->filter("tr")); - - foreach($dates as $date) { - $this->assertLessThanOrEqual($dateTo, $date); - } - }); - - } - /** * this function iterate on row from results of events and return the content - * of the second column (which should contains the date) in DateTime objects - * - * @param \Symfony\Component\DomCrawler\Crawler $trs - * @return \DateTime[] + * of the second column (which should contains the date) in DateTime objects. + * + * @return DateTime[] */ private function iterateOnRowsToFindDate(\Symfony\Component\DomCrawler\Crawler $trs) { - $months = array( - "janvier" => 1, - "février" => 2, - "mars" => 3, - "avril" => 4, - "mai" => 5, - "juin" => 6, - "juillet" => 7, - "août" => 8, - "septembre" => 9, - "octobre" => 10, - "novembre" => 11, - "décembre" => 12 - ); - - - $results = $trs->each(function($tr, $i) use ($months) { + $months = [ + 'janvier' => 1, + 'février' => 2, + 'mars' => 3, + 'avril' => 4, + 'mai' => 5, + 'juin' => 6, + 'juillet' => 7, + 'août' => 8, + 'septembre' => 9, + 'octobre' => 10, + 'novembre' => 11, + 'décembre' => 12, + ]; + + $results = $trs->each(function ($tr, $i) use ($months) { // we skip the first row - if ($i > 0) { + if (0 < $i) { // get the second node, which should contains a date - $tdDate = $tr->filter("td")->eq(1); + $tdDate = $tr->filter('td')->eq(1); // transform the date, which should be in french, into a DateTime object - $parts = explode(" ", $tdDate->text()); - return \DateTime::createFromFormat("Y-m-d", $parts[2]. - "-".$months[$parts[1]]."-".$parts[0]); + $parts = explode(' ', $tdDate->text()); + + return DateTime::createFromFormat('Y-m-d', $parts[2] . + '-' . $months[$parts[1]] . '-' . $parts[0]); } }); - + // remove the first row unset($results[0]); - + return $results; } - - /** - * Test that a user connected with an user with the wrong center does not - * see the events - */ - public function testDisplayAllWrongUser() - { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center b_social', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@events printemps' - )); - - $this->assertEquals(0, $crawler->filter('tr:contains("Printemps")')->count(), - 'assert that the word "printemps" is present'); - - } - - - } diff --git a/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php b/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php index 3e7c67562..279406300 100644 --- a/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php +++ b/src/Bundle/ChillEventBundle/Timeline/TimelineEventProvider.php @@ -1,41 +1,29 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\EventBundle\Timeline; use Chill\EventBundle\Entity\Event; use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Timeline\TimelineProviderInterface; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadata; +use LogicException; +use RuntimeException; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Mapping\ClassMetadata; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\User; /** - * Class TimelineEventProvider - * - * @package Chill\EventBundle\Timeline - * @author Mathieu Jaumotte jaum_mathieu@collectifs.net + * Class TimelineEventProvider. */ class TimelineEventProvider implements TimelineProviderInterface { @@ -43,23 +31,19 @@ class TimelineEventProvider implements TimelineProviderInterface * @var EntityManager */ protected $em; - + /** * @var AuthorizationHelper */ protected $helper; - + /** * @var User */ protected $user; - + /** * TimelineEventProvider constructor. - * - * @param EntityManager $em - * @param AuthorizationHelper $helper - * @param TokenStorageInterface $storage */ public function __construct( EntityManager $em, @@ -68,43 +52,103 @@ class TimelineEventProvider implements TimelineProviderInterface ) { $this->em = $em; $this->helper = $helper; + if (!$storage->getToken()->getUser() instanceof User) { - throw new \RuntimeException('A user should be authenticated !'); + throw new RuntimeException('A user should be authenticated !'); } $this->user = $storage->getToken()->getUser(); } - + /** * @param string $context - * @param array $args - * @return array|string[] + * * @throws \Doctrine\ORM\Mapping\MappingException + * + * @return array|string[] */ public function fetchQuery($context, array $args) { $this->checkContext($context); - + $metadataEvent = $this->em->getClassMetadata('ChillEventBundle:Event'); $metadataParticipation = $this->em->getClassMetadata('ChillEventBundle:Participation'); $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); - - $query = array( - 'id' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('id'), + + return [ + 'id' => $metadataEvent->getTableName() . '.' . $metadataEvent->getColumnName('id'), 'type' => 'event', - 'date' => $metadataEvent->getTableName().'.'.$metadataEvent->getColumnName('date'), + 'date' => $metadataEvent->getTableName() . '.' . $metadataEvent->getColumnName('date'), 'FROM' => $this->getFromClause($metadataEvent, $metadataParticipation, $metadataPerson), - 'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']) - ); - - return $query; + 'WHERE' => $this->getWhereClause($metadataEvent, $metadataParticipation, $metadataPerson, $args['person']), + ]; } - + + /** + * @return array|mixed[] + */ + public function getEntities(array $ids) + { + $events = $this->em->getRepository(Event::class) + ->findBy(['id' => $ids]); + + $result = []; + + foreach ($events as $event) { + $result[$event->getId()] = $event; + } + + return $result; + } + + /** + * @param Event $entity + * @param string $context + * + * @return array|mixed[] + */ + public function getEntityTemplate($entity, $context, array $args) + { + $this->checkContext($context); + + return [ + 'template' => 'ChillEventBundle:Timeline:event_person_context.html.twig', + 'template_data' => [ + 'event' => $entity, + 'person' => $args['person'], + 'user' => $this->user, + ], + ]; + } + + /** + * @param string $type + * + * @return bool + */ + public function supportsType($type) + { + return 'event' === $type; + } + + /** + * check if the context is supported. + * + * @param string $context + * + * @throws LogicException if the context is not supported + */ + private function checkContext($context) + { + if ('person' !== $context) { + throw new LogicException("The context '{$context}' is not " + . "supported. Currently only 'person' is supported"); + } + } + /** - * @param ClassMetadata $metadataEvent - * @param ClassMetadata $metadataParticipation - * @param ClassMetadata $metadataPerson - * @return string * @throws \Doctrine\ORM\Mapping\MappingException + * + * @return string */ private function getFromClause( ClassMetadata $metadataEvent, @@ -113,30 +157,25 @@ class TimelineEventProvider implements TimelineProviderInterface ) { $eventParticipationMapping = $metadataParticipation->getAssociationMapping('event'); $participationPersonMapping = $metadataParticipation->getAssociationMapping('person'); - + return $metadataEvent->getTableName() + . ' JOIN ' . $metadataParticipation->getTableName() + . ' ON ' . $metadataParticipation->getTableName() + . '.' . $eventParticipationMapping['joinColumns'][0]['name'] + . ' = ' . $metadataEvent->getTableName() + . '.' . $eventParticipationMapping['joinColumns'][0]['referencedColumnName'] - .' JOIN '.$metadataParticipation->getTableName() - .' ON ' .$metadataParticipation->getTableName() - .'.' .$eventParticipationMapping['joinColumns'][0]['name'] - .' = ' .$metadataEvent->getTableName() - .'.' .$eventParticipationMapping['joinColumns'][0]['referencedColumnName'] - - .' JOIN '.$metadataPerson->getTableName() - .' ON ' .$metadataPerson->getTableName() - .'.' .$participationPersonMapping['joinColumns'][0]['referencedColumnName'] - .' = ' .$metadataParticipation->getTableName() - .'.' .$participationPersonMapping['joinColumns'][0]['name'] - ; + . ' JOIN ' . $metadataPerson->getTableName() + . ' ON ' . $metadataPerson->getTableName() + . '.' . $participationPersonMapping['joinColumns'][0]['referencedColumnName'] + . ' = ' . $metadataParticipation->getTableName() + . '.' . $participationPersonMapping['joinColumns'][0]['name']; } - + /** - * @param ClassMetadata $metadataEvent - * @param ClassMetadata $metadataParticipation - * @param ClassMetadata $metadataPerson - * @param Person $person - * @return string * @throws \Doctrine\ORM\Mapping\MappingException + * + * @return string */ private function getWhereClause( ClassMetadata $metadataEvent, @@ -145,23 +184,28 @@ class TimelineEventProvider implements TimelineProviderInterface Person $person ) { $role = new Role('CHILL_EVENT_SEE'); - + $reachableCenters = $this->helper->getReachableCenters($this->user, $role); $associationMapping = $metadataParticipation->getAssociationMapping('person'); - + if (count($reachableCenters) === 0) { return 'FALSE = TRUE'; } - - $whereClause = sprintf( '%s = %d', + + $whereClause = sprintf( + '%s = %d', $associationMapping['joinColumns'][0]['name'], - $person->getId()); - + $person->getId() + ); + // and - $centerAndScopeLines = array(); + $centerAndScopeLines = []; + foreach ($reachableCenters as $center) { $reachableCircleId = array_map( - function (Scope $scope) { return $scope->getId(); }, + function (Scope $scope) { + return $scope->getId(); + }, $this->helper->getReachableCircles($this->user, $role, $person->getCenter()) ); $centerAndScopeLines[] = sprintf( @@ -174,68 +218,8 @@ class TimelineEventProvider implements TimelineProviderInterface implode(',', $reachableCircleId) ); } - $whereClause .= ' AND ('. implode(' OR ', $centerAndScopeLines) .')'; - + $whereClause .= ' AND (' . implode(' OR ', $centerAndScopeLines) . ')'; + return $whereClause; } - - /** - * check if the context is supported - * - * @param string $context - * @throws \LogicException if the context is not supported - */ - private function checkContext($context) - { - if ($context !== 'person') { - throw new \LogicException("The context '$context' is not " - . "supported. Currently only 'person' is supported"); - } - } - - /** - * @param string $type - * @return bool - */ - public function supportsType($type) - { - return $type === 'event'; - } - - /** - * @param array $ids - * @return array|mixed[] - */ - public function getEntities(array $ids) { - - $events = $this->em->getRepository(Event::class) - ->findBy(array('id' => $ids)); - - $result = array(); - foreach ($events as $event) { - $result[$event->getId()] = $event; - } - return $result; - } - - /** - * @param Event $entity - * @param string $context - * @param array $args - * @return array|mixed[] - */ - public function getEntityTemplate($entity, $context, array $args) { - - $this->checkContext($context); - - return array( - 'template' => 'ChillEventBundle:Timeline:event_person_context.html.twig', - 'template_data' => array( - 'event' => $entity, - 'person' => $args['person'], - 'user' => $this->user - ) - ); - } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillEventBundle/migrations/Version20160318111334.php b/src/Bundle/ChillEventBundle/migrations/Version20160318111334.php index 50671534e..a364aa4d4 100644 --- a/src/Bundle/ChillEventBundle/migrations/Version20160318111334.php +++ b/src/Bundle/ChillEventBundle/migrations/Version20160318111334.php @@ -1,18 +1,51 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_event_role DROP CONSTRAINT FK_AA714E54C54C8C93'); + $this->addSql('ALTER TABLE chill_event_status DROP CONSTRAINT FK_A6CC85D0C54C8C93'); + $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768ACD60322AC'); + $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768AC6BF700BD'); + $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768AC71F7E88B'); + // drop center_id constraint + $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC85932F377'); + // drop type_id constraint + $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC8C54C8C93'); + // drop circle_id constraint + $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC870EE2FF6'); + + $this->addSql('DROP SEQUENCE chill_event_event_type_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_event_role_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_event_status_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_event_event_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_event_participation_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_event_event_type'); + $this->addSql('DROP TABLE chill_event_role'); + $this->addSql('DROP TABLE chill_event_status'); + $this->addSql('DROP TABLE chill_event_event'); + $this->addSql('DROP TABLE chill_event_participation'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -62,7 +95,7 @@ class Version20160318111334 extends AbstractMigration $this->addSql('CREATE INDEX IDX_FA320FC85932F377 ON chill_event_event (center_id)'); $this->addSql('CREATE INDEX IDX_FA320FC8C54C8C93 ON chill_event_event (type_id)'); $this->addSql('CREATE INDEX IDX_FA320FC870EE2FF6 ON chill_event_event (circle_id)'); - + $this->addSql('ALTER TABLE chill_event_event ' . 'ADD CONSTRAINT FK_FA320FC85932F377 FOREIGN KEY (center_id) ' . 'REFERENCES centers (id) ' @@ -103,39 +136,5 @@ class Version20160318111334 extends AbstractMigration . 'FOREIGN KEY (status_id) ' . 'REFERENCES chill_event_status (id) ' . 'NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_event_role DROP CONSTRAINT FK_AA714E54C54C8C93'); - $this->addSql('ALTER TABLE chill_event_status DROP CONSTRAINT FK_A6CC85D0C54C8C93'); - $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768ACD60322AC'); - $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768AC6BF700BD'); - $this->addSql('ALTER TABLE chill_event_participation DROP CONSTRAINT FK_4E7768AC71F7E88B'); - // drop center_id constraint - $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC85932F377'); - // drop type_id constraint - $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC8C54C8C93'); - // drop circle_id constraint - $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC870EE2FF6'); - - $this->addSql('DROP SEQUENCE chill_event_event_type_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_event_role_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_event_status_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_event_event_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_event_participation_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_event_event_type'); - $this->addSql('DROP TABLE chill_event_role'); - $this->addSql('DROP TABLE chill_event_status'); - $this->addSql('DROP TABLE chill_event_event'); - $this->addSql('DROP TABLE chill_event_participation'); - } } diff --git a/src/Bundle/ChillEventBundle/migrations/Version20190110140538.php b/src/Bundle/ChillEventBundle/migrations/Version20190110140538.php index 5018c9f1a..b0b676362 100644 --- a/src/Bundle/ChillEventBundle/migrations/Version20190110140538.php +++ b/src/Bundle/ChillEventBundle/migrations/Version20190110140538.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_event_event ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); - $this->addSql('ALTER TABLE chill_event_event ALTER date DROP DEFAULT'); - - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - + $this->addSql('ALTER TABLE chill_event_event ALTER date TYPE DATE'); $this->addSql('ALTER TABLE chill_event_event ALTER date DROP DEFAULT'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_event_event ALTER date TYPE TIMESTAMP(0) WITHOUT TIME ZONE'); + $this->addSql('ALTER TABLE chill_event_event ALTER date DROP DEFAULT'); + } } diff --git a/src/Bundle/ChillEventBundle/migrations/Version20190115140042.php b/src/Bundle/ChillEventBundle/migrations/Version20190115140042.php index 21e476948..35b586907 100644 --- a/src/Bundle/ChillEventBundle/migrations/Version20190115140042.php +++ b/src/Bundle/ChillEventBundle/migrations/Version20190115140042.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_event_event ADD moderator_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_event_event ADD CONSTRAINT FK_FA320FC8D0AFA354 FOREIGN KEY (moderator_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('CREATE INDEX IDX_FA320FC8D0AFA354 ON chill_event_event (moderator_id)'); - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs @@ -29,4 +28,14 @@ final class Version20190115140042 extends AbstractMigration $this->addSql('DROP INDEX IDX_FA320FC8D0AFA354'); $this->addSql('ALTER TABLE chill_event_event DROP moderator_id'); } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_event_event ADD moderator_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_event_event ADD CONSTRAINT FK_FA320FC8D0AFA354 FOREIGN KEY (moderator_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_FA320FC8D0AFA354 ON chill_event_event (moderator_id)'); + } } diff --git a/src/Bundle/ChillEventBundle/migrations/Version20190201143121.php b/src/Bundle/ChillEventBundle/migrations/Version20190201143121.php index 7edbb4d52..7c6d0abc8 100644 --- a/src/Bundle/ChillEventBundle/migrations/Version20190201143121.php +++ b/src/Bundle/ChillEventBundle/migrations/Version20190201143121.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT fk_fa320fc8d0afa354'); + $this->addSql('ALTER TABLE chill_event_event ADD CONSTRAINT fk_fa320fc8d0afa354 FOREIGN KEY (moderator_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -18,14 +36,4 @@ final class Version20190201143121 extends AbstractMigration $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT FK_FA320FC8D0AFA354'); $this->addSql('ALTER TABLE chill_event_event ADD CONSTRAINT FK_FA320FC8D0AFA354 FOREIGN KEY (moderator_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_event_event DROP CONSTRAINT fk_fa320fc8d0afa354'); - $this->addSql('ALTER TABLE chill_event_event ADD CONSTRAINT fk_fa320fc8d0afa354 FOREIGN KEY (moderator_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } } diff --git a/src/Bundle/ChillFamilyMembersBundle/ChillAMLIFamilyMembersBundle.php b/src/Bundle/ChillFamilyMembersBundle/ChillAMLIFamilyMembersBundle.php index da512a9aa..90d73e461 100644 --- a/src/Bundle/ChillFamilyMembersBundle/ChillAMLIFamilyMembersBundle.php +++ b/src/Bundle/ChillFamilyMembersBundle/ChillAMLIFamilyMembersBundle.php @@ -1,5 +1,12 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\FamilyMembersBundle\Config; + class ConfigRepository { /** - * - * @var array - */ - protected $links; - - /** - * - * @var array - */ - protected $professionalSituations; - - /** - * * @var array */ protected $familialSituations; - + + /** + * @var array + */ + protected $links; + + /** + * @var array + */ + protected $professionalSituations; + public function __construct($links, $professionnalSituations, $familialSituations) { $this->links = $links; $this->professionalSituations = $professionnalSituations ?? []; $this->familialSituations = $familialSituations ?? []; } - + + public function getFamilialSituationsLabels() + { + return $this->normalizeConfig($this->familialSituations); + } + /** - * * @return array where keys are the link's keys and label the links label */ public function getLinksLabels() { return $this->normalizeConfig($this->links); } - + public function getProfessionalSituationsLabels() { return $this->normalizeConfig($this->professionalSituations); } - - public function hasProfessionalSituation(): bool - { - return count($this->professionalSituations) > 0; - } - - public function getFamilialSituationsLabels() - { - return $this->normalizeConfig($this->familialSituations); - } - + public function hasFamilialSituation(): bool { return count($this->familialSituations) > 0; } - + + public function hasProfessionalSituation(): bool + { + return count($this->professionalSituations) > 0; + } + private function normalizeConfig($config) { - $els = array(); - + $els = []; + foreach ($config as $definition) { $els[$definition['key']] = $this->normalizeLabel($definition['labels']); } - + return $els; } - - private function normalizeLabel($labels) + + private function normalizeLabel($labels) { - $normalizedLabels = array(); - + $normalizedLabels = []; + foreach ($labels as $labelDefinition) { $normalizedLabels[$labelDefinition['lang']] = $labelDefinition['label']; } - + return $normalizedLabels; } - } diff --git a/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php b/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php index 8c534d838..6f591267d 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php +++ b/src/Bundle/ChillFamilyMembersBundle/Controller/FamilyMemberController.php @@ -1,39 +1,43 @@ chillMainLogger = $chillMainLogger; } - /** * @Route( - * "{_locale}/family-members/family-members/by-person/{id}", - * name="chill_family_members_family_members_index" + * "{_locale}/family-members/family-members/{id}/delete", + * name="chill_family_members_family_members_delete" * ) - */ - public function indexAction(Person $person) - { - $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person); - - $familyMembers = $this->em - ->getRepository(FamilyMember::class) - ->findByPerson($person); - - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', array( - 'person' => $person, - 'familyMembers' => $familyMembers - )); - } - - /** - * @Route( - * "{_locale}/family-members/family-members/by-person/{id}/new", - * name="chill_family_members_family_members_new" - * ) - */ - public function newAction(Person $person, Request $request) - { - $familyMember = (new FamilyMember()) - ->setPerson($person) - ; - - $this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember); - - $form = $this->createForm(FamilyMemberType::class, $familyMember); - $form->add('submit', SubmitType::class); - - $form->handleRequest($request); - - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($familyMember); - $em->flush(); - - $this->addFlash('success', $this->translator->trans('Family member created')); - - return $this->redirectToRoute('chill_family_members_family_members_index', [ - 'id' => $person->getId() - ]); - } - - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', array( - 'form' => $form->createView(), - 'person' => $person - )); - } - - /** - * @Route( - * "{_locale}/family-members/family-members/{id}/edit", - * name="chill_family_members_family_members_edit" - * ) - */ - public function editAction(FamilyMember $familyMember, Request $request) - { - $this->denyAccessUnlessGranted(FamilyMemberVoter::UPDATE, $familyMember); - - $form = $this->createForm(FamilyMemberType::class, $familyMember); - $form->add('submit', SubmitType::class); - - $form->handleRequest($request); - - if ($form->isSubmitted() and $form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->flush(); - - $this->addFlash('success', $this->translator->trans('Family member updated')); - - return $this->redirectToRoute('chill_family_members_family_members_index', [ - 'id' => $familyMember->getPerson()->getId() - ]); - } - - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', array( - 'familyMember' => $familyMember, - 'form' => $form->createView(), - 'person' => $familyMember->getPerson() - )); - } - - /** - * - * @Route( - * "{_locale}/family-members/family-members/{id}/delete", - * name="chill_family_members_family_members_delete" - * ) - * - * @param FamilyMember $familyMember - * @param Request $request + * * @return \Symfony\Component\BrowserKit\Response */ public function deleteAction(FamilyMember $familyMember, Request $request) @@ -157,48 +67,136 @@ class FamilyMemberController extends Controller $form->handleRequest($request); if ($form->isValid()) { - $this->chillMainLogger->notice("A family member has been removed", array( - 'by_user' => $this->getUser()->getUsername(), - 'family_member_id' => $familyMember->getId(), - 'name' => $familyMember->getFirstname()." ".$familyMember->getLastname(), - 'link' => $familyMember->getLink() - )); + $this->chillMainLogger->notice('A family member has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'family_member_id' => $familyMember->getId(), + 'name' => $familyMember->getFirstname() . ' ' . $familyMember->getLastname(), + 'link' => $familyMember->getLink(), + ]); $em = $this->getDoctrine()->getManager(); $em->remove($familyMember); $em->flush(); $this->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( - 'id' => $familyMember->getPerson()->getId() - )); + return $this->redirectToRoute('chill_family_members_family_members_index', [ + 'id' => $familyMember->getPerson()->getId(), + ]); } } - - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', array( - 'familyMember' => $familyMember, - 'delete_form' => $form->createView() - )); + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:confirm_delete.html.twig', [ + 'familyMember' => $familyMember, + 'delete_form' => $form->createView(), + ]); } - + /** * @Route( - * "{_locale}/family-members/family-members/{id}/view", - * name="chill_family_members_family_members_view" + * "{_locale}/family-members/family-members/{id}/edit", + * name="chill_family_members_family_members_edit" + * ) + */ + public function editAction(FamilyMember $familyMember, Request $request) + { + $this->denyAccessUnlessGranted(FamilyMemberVoter::UPDATE, $familyMember); + + $form = $this->createForm(FamilyMemberType::class, $familyMember); + $form->add('submit', SubmitType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() and $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->flush(); + + $this->addFlash('success', $this->translator->trans('Family member updated')); + + return $this->redirectToRoute('chill_family_members_family_members_index', [ + 'id' => $familyMember->getPerson()->getId(), + ]); + } + + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:edit.html.twig', [ + 'familyMember' => $familyMember, + 'form' => $form->createView(), + 'person' => $familyMember->getPerson(), + ]); + } + + /** + * @Route( + * "{_locale}/family-members/family-members/by-person/{id}", + * name="chill_family_members_family_members_index" + * ) + */ + public function indexAction(Person $person) + { + $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $person); + + $familyMembers = $this->em + ->getRepository(FamilyMember::class) + ->findByPerson($person); + + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:index.html.twig', [ + 'person' => $person, + 'familyMembers' => $familyMembers, + ]); + } + + /** + * @Route( + * "{_locale}/family-members/family-members/by-person/{id}/new", + * name="chill_family_members_family_members_new" + * ) + */ + public function newAction(Person $person, Request $request) + { + $familyMember = (new FamilyMember()) + ->setPerson($person); + + $this->denyAccessUnlessGranted(FamilyMemberVoter::CREATE, $familyMember); + + $form = $this->createForm(FamilyMemberType::class, $familyMember); + $form->add('submit', SubmitType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() and $form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($familyMember); + $em->flush(); + + $this->addFlash('success', $this->translator->trans('Family member created')); + + return $this->redirectToRoute('chill_family_members_family_members_index', [ + 'id' => $person->getId(), + ]); + } + + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:new.html.twig', [ + 'form' => $form->createView(), + 'person' => $person, + ]); + } + + /** + * @Route( + * "{_locale}/family-members/family-members/{id}/view", + * name="chill_family_members_family_members_view" * ) */ public function viewAction(FamilyMember $familyMember) { $this->denyAccessUnlessGranted(FamilyMemberVoter::SHOW, $familyMember); - - return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', array( - 'familyMember' => $familyMember - )); + + return $this->render('ChillAMLIFamilyMembersBundle:FamilyMember:view.html.twig', [ + 'familyMember' => $familyMember, + ]); } - + /** * Creates a form to delete a help request entity by id. * @@ -210,9 +208,7 @@ class FamilyMemberController extends Controller { return $this->createFormBuilder() ->setMethod(Request::METHOD_DELETE) - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); } - } diff --git a/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/ChillAMLIFamilyMembersExtension.php b/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/ChillAMLIFamilyMembersExtension.php index 58d994d66..3e595dcb6 100644 --- a/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/ChillAMLIFamilyMembersExtension.php +++ b/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/ChillAMLIFamilyMembersExtension.php @@ -1,32 +1,36 @@ processConfiguration($configuration, $configs); - + $this->storeConfig($container, $config); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); $loader->load('services/config.yml'); $loader->load('services/form.yml'); $loader->load('services/controller.yml'); @@ -34,45 +38,48 @@ class ChillAMLIFamilyMembersExtension extends Extension implements PrependExtens $loader->load('services/menu.yml'); $loader->load('services/templating.yml'); } - - private function storeConfig(ContainerBuilder $container, array $config) - { - $container->setParameter('chill_family_members.links', $config['links']); - $container->setParameter('chill_family_members.professionnal_situations', - $config['professionnal_situations']); - $container->setParameter('chill_family_members.familial_situations', - $config['familial_situations']); - } - + public function prepend(ContainerBuilder $container) { $this->prependAuthorization($container); $this->prependRoutes($container); } - - protected function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - FamilyMemberVoter::UPDATE => [FamilyMemberVoter::SHOW], - FamilyMemberVoter::CREATE => [FamilyMemberVoter::SHOW] - ) - )); - } - + /* (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface::prepend() */ - public function prependRoutes(ContainerBuilder $container) + public function prependRoutes(ContainerBuilder $container) { //add routes for custom bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillAMLIFamilyMembersBundle/Resources/config/routing.yml' - ) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillAMLIFamilyMembersBundle/Resources/config/routing.yml', + ], + ], + ]); } + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + FamilyMemberVoter::UPDATE => [FamilyMemberVoter::SHOW], + FamilyMemberVoter::CREATE => [FamilyMemberVoter::SHOW], + ], + ]); + } + + private function storeConfig(ContainerBuilder $container, array $config) + { + $container->setParameter('chill_family_members.links', $config['links']); + $container->setParameter( + 'chill_family_members.professionnal_situations', + $config['professionnal_situations'] + ); + $container->setParameter( + 'chill_family_members.familial_situations', + $config['familial_situations'] + ); + } } diff --git a/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/Configuration.php index 90ab9ba3e..69a346912 100644 --- a/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillFamilyMembersBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ children() - ->arrayNode('links')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('key')->isRequired()->cannotBeEmpty() - ->info('the key stored in database') - ->example('grandson') - ->end() - ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('Petit-fils') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->arrayNode('professionnal_situations')->isRequired() - ->info("the list of professional situations. If empty, the field will not be shown") - ->arrayPrototype() - ->children() -->scalarNode('key')->isRequired()->cannotBeEmpty() - ->info('the key stored in database') - ->example('student') - ->end() - ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('Étudiant') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->arrayNode('familial_situations')->isRequired() - ->info("the list of familial situations. If empty, the field will not be shown") - ->arrayPrototype() - ->children() -->scalarNode('key')->isRequired()->cannotBeEmpty() - ->info('the key stored in database') - ->example('half_time_keeping') - ->end() - ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() - ->arrayPrototype() - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('En garde alternée') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ; + ->arrayNode('links')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('key')->isRequired()->cannotBeEmpty() + ->info('the key stored in database') + ->example('grandson') + ->end() + ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('Petit-fils') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->arrayNode('professionnal_situations')->isRequired() + ->info('the list of professional situations. If empty, the field will not be shown') + ->arrayPrototype() + ->children() + ->scalarNode('key')->isRequired()->cannotBeEmpty() + ->info('the key stored in database') + ->example('student') + ->end() + ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('Étudiant') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->arrayNode('familial_situations')->isRequired() + ->info('the list of familial situations. If empty, the field will not be shown') + ->arrayPrototype() + ->children() + ->scalarNode('key')->isRequired()->cannotBeEmpty() + ->info('the key stored in database') + ->example('half_time_keeping') + ->end() + ->arrayNode('labels')->isRequired()->requiresAtLeastOneElement() + ->arrayPrototype() + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('En garde alternée') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end(); return $treeBuilder; } diff --git a/src/Bundle/ChillFamilyMembersBundle/Entity/AbstractFamilyMember.php b/src/Bundle/ChillFamilyMembersBundle/Entity/AbstractFamilyMember.php index 36da186d0..50da10bcf 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Entity/AbstractFamilyMember.php +++ b/src/Bundle/ChillFamilyMembersBundle/Entity/AbstractFamilyMember.php @@ -1,53 +1,60 @@ + * @ORM\MappedSuperclass */ abstract class AbstractFamilyMember implements HasCenterInterface { - const FAMILIAL_SITUATION = [ - 'a_charge'=> 'A charge', - 'garde_alternee'=> 'Garde alternée', - 'droit_de_visite'=> 'Droit de visite et d\'hébergement', - 'non_a_charge' => 'Non à charge', - ]; + public const FAMILIAL_SITUATION = [ + 'a_charge' => 'A charge', + 'garde_alternee' => 'Garde alternée', + 'droit_de_visite' => 'Droit de visite et d\'hébergement', + 'non_a_charge' => 'Non à charge', + ]; -/** - * - * @var Person - * @ORM\ManyToOne( - * targetEntity="\Chill\PersonBundle\Entity\Person" - * ) - */ - private $person; - /** + * @var date_immutable|null * - * @var MaritalStatus - * @ORM\ManyToOne( - * targetEntity="\Chill\PersonBundle\Entity\MaritalStatus" + * @ORM\Column(name="birthdate", type="date_immutable", nullable=true) + * @Assert\Date + */ + private $birthdate; + + /** + * @var DateTimeImmutable|null + * + * @ORM\Column(name="endDate", type="datetime_immutable", nullable=true) + * @Assert\Date + * @Assert\GreaterThan( + * propertyPath="startDate", + * message="The membership's end date should be after the start date" * ) */ - private $maritalStatus; + private $endDate; /** * @var string - * - * @ORM\Column(name="lastname", type="string", length=255) + * @ORM\Column(name="familial_situation", type="string", length=200, nullable=true) */ - private $lastname = ''; + private $familialSituation; /** * @var string @@ -64,12 +71,34 @@ abstract class AbstractFamilyMember implements HasCenterInterface private $gender = ''; /** - * @var date_immutable|null + * @var string * - * @ORM\Column(name="birthdate", type="date_immutable", nullable=true) - * @Assert\Date() + * @ORM\Column(name="lastname", type="string", length=255) */ - private $birthdate; + private $lastname = ''; + + /** + * @var string + * + * @ORM\Column(name="link", type="string", length=255) + */ + private $link = ''; + + /** + * @var MaritalStatus + * @ORM\ManyToOne( + * targetEntity="\Chill\PersonBundle\Entity\MaritalStatus" + * ) + */ + private $maritalStatus; + + /** + * @var Person + * @ORM\ManyToOne( + * targetEntity="\Chill\PersonBundle\Entity\Person" + * ) + */ + private $person; /** * @var string @@ -79,57 +108,67 @@ abstract class AbstractFamilyMember implements HasCenterInterface private $professionnalSituation = ''; /** - * @var string - * - * @ORM\Column(name="link", type="string", length=255) - */ - private $link = ''; - - /** - * - * @var string - * @ORM\Column(name="familial_situation", type="string", length=200, nullable=true) - */ - private $familialSituation; - - /** - * @var \DateTimeImmutable + * @var DateTimeImmutable * * @ORM\Column(name="startDate", type="datetime_immutable") - * @Assert\NotNull() - * @Assert\Date() + * @Assert\NotNull + * @Assert\Date */ private $startDate; - /** - * @var \DateTimeImmutable|null - * - * @ORM\Column(name="endDate", type="datetime_immutable", nullable=true) - * @Assert\Date() - * @Assert\GreaterThan( - * propertyPath="startDate", - * message="The membership's end date should be after the start date" - * ) - */ - private $endDate; - public function __construct() { - $this->setStartDate(new \DateTimeImmutable('now')); + $this->setStartDate(new DateTimeImmutable('now')); } - - /** - * Set lastname. - * - * @param string $lastname - * - * @return FamilyMember - */ - public function setLastname($lastname) - { - $this->lastname = (string) $lastname; - return $this; + /** + * Get birthdate. + * + * @return date_immutable|null + */ + public function getBirthdate() + { + return $this->birthdate; + } + + public function getCenter(): \Chill\MainBundle\Entity\Center + { + return $this->getPerson()->getCenter(); + } + + /** + * Get endDate. + * + * @return DateTimeImmutable|null + */ + public function getEndDate() + { + return $this->endDate; + } + + public function getFamilialSituation() + { + return $this->familialSituation; + } + + /** + * Get firstname. + * + * @return string + */ + public function getFirstname() + { + return $this->firstname; + } + + /** + * Get gender. + * + * @return string + */ + public function getGender() + { + return $this->gender; } /** @@ -142,6 +181,91 @@ abstract class AbstractFamilyMember implements HasCenterInterface return $this->lastname; } + /** + * Get link. + * + * @return string + */ + public function getLink() + { + return $this->link; + } + + /** + * @return MaritalStatus + */ + public function getMaritalStatus() + { + return $this->maritalStatus; + } + + /** + * @return Person + */ + public function getPerson() + { + return $this->person; + } + + /** + * Get professionnalSituation. + * + * @return string + */ + public function getProfessionnalSituation() + { + return $this->professionnalSituation; + } + + /** + * Get startDate. + * + * @return DateTimeImmutable + */ + public function getStartDate() + { + return $this->startDate; + } + + /** + * Set birthdate. + * + * @return FamilyMember + */ + public function setBirthdate(?DateTimeInterface $birthdate = null) + { + if ($birthdate instanceof DateTime) { + $this->birthdate = DateTimeImmutable::createFromMutable($birthdate); + } elseif (null === $birthdate || $birthdate instanceof DateTimeImmutable) { + $this->birthdate = $birthdate; + } + + return $this; + } + + /** + * Set endDate. + * + * @return FamilyMember + */ + public function setEndDate(?DateTimeInterface $endDate = null) + { + if ($endDate instanceof DateTime) { + $this->endDate = DateTimeImmutable::createFromMutable($endDate); + } elseif ($endDate instanceof DateTimeImmutable || null === $endDate) { + $this->endDate = $endDate; + } + + return $this; + } + + public function setFamilialSituation($familialSituation) + { + $this->familialSituation = $familialSituation; + + return $this; + } + /** * Set firstname. * @@ -156,16 +280,6 @@ abstract class AbstractFamilyMember implements HasCenterInterface return $this; } - /** - * Get firstname. - * - * @return string - */ - public function getFirstname() - { - return $this->firstname; - } - /** * Set gender. * @@ -181,67 +295,19 @@ abstract class AbstractFamilyMember implements HasCenterInterface } /** - * Get gender. + * Set lastname. * - * @return string - */ - public function getGender() - { - return $this->gender; - } - - /** - * Set birthdate. - * - * @param \DateTimeInterface|null $birthdate + * @param string $lastname * * @return FamilyMember */ - public function setBirthdate(\DateTimeInterface $birthdate = null) + public function setLastname($lastname) { - if ($birthdate instanceof \DateTime) { - $this->birthdate = \DateTimeImmutable::createFromMutable($birthdate); - } elseif ($birthdate === null || $birthdate instanceof \DateTimeImmutable) { - $this->birthdate = $birthdate; - } + $this->lastname = (string) $lastname; return $this; } - /** - * Get birthdate. - * - * @return date_immutable|null - */ - public function getBirthdate() - { - return $this->birthdate; - } - - /** - * Set professionnalSituation. - * - * @param string $professionnalSituation - * - * @return FamilyMember - */ - public function setProfessionnalSituation($professionnalSituation) - { - $this->professionnalSituation = (string) $professionnalSituation; - - return $this; - } - - /** - * Get professionnalSituation. - * - * @return string - */ - public function getProfessionnalSituation() - { - return $this->professionnalSituation; - } - /** * Set link. * @@ -257,127 +323,56 @@ abstract class AbstractFamilyMember implements HasCenterInterface } /** - * Get link. + * @param MaritalStatus $maritalStatus * - * @return string + * @return $this */ - public function getLink() + public function setMaritalStatus(?MaritalStatus $maritalStatus = null) { - return $this->link; - } - - public function getFamilialSituation() - { - return $this->familialSituation; - } - - public function setFamilialSituation($familialSituation) - { - $this->familialSituation = $familialSituation; - - return $this; - } - - /** - * Set startDate. - * - * @param \DateTimeImmutable $startDate - * - * @return FamilyMember - */ - public function setStartDate(\DateTimeInterface $startDate) - { - if ($startDate instanceof \DateTime) { - $this->startDate = \DateTimeImmutable::createFromMutable($startDate); - } elseif (NULL === $startDate || $startDate instanceof \DateTimeImmutable) { - $this->startDate = $startDate; - } + $this->maritalStatus = $maritalStatus; return $this; } /** - * Get startDate. - * - * @return \DateTimeImmutable - */ - public function getStartDate() - { - return $this->startDate; - } - - /** - * Set endDate. - * - * @param \DateTimeInterface|null $endDate - * - * @return FamilyMember - */ - public function setEndDate(\DateTimeInterface $endDate = null) - { - if ($endDate instanceof \DateTime) { - $this->endDate = \DateTimeImmutable::createFromMutable($endDate); - } elseif ($endDate instanceof \DateTimeImmutable || $endDate === null) { - $this->endDate = $endDate; - } - - return $this; - } - - /** - * Get endDate. - * - * @return \DateTimeImmutable|null - */ - public function getEndDate() - { - return $this->endDate; - } - - /** - * - * @return Person - */ - public function getPerson() - { - return $this->person; - } - - /** - * - * @return MaritalStatus - */ - public function getMaritalStatus() - { - return $this->maritalStatus; - } - - /** - * - * @param Person $person * @return $this */ public function setPerson(Person $person) { $this->person = $person; - + return $this; } /** - * - * @param MaritalStatus $maritalStatus - * @return $this + * Set professionnalSituation. + * + * @param string $professionnalSituation + * + * @return FamilyMember */ - public function setMaritalStatus(MaritalStatus $maritalStatus = null) + public function setProfessionnalSituation($professionnalSituation) { - $this->maritalStatus = $maritalStatus; - + $this->professionnalSituation = (string) $professionnalSituation; + return $this; } - public function getCenter(): \Chill\MainBundle\Entity\Center + /** + * Set startDate. + * + * @param DateTimeImmutable $startDate + * + * @return FamilyMember + */ + public function setStartDate(DateTimeInterface $startDate) { - return $this->getPerson()->getCenter(); + if ($startDate instanceof DateTime) { + $this->startDate = DateTimeImmutable::createFromMutable($startDate); + } elseif (null === $startDate || $startDate instanceof DateTimeImmutable) { + $this->startDate = $startDate; + } + + return $this; } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Entity/FamilyMember.php b/src/Bundle/ChillFamilyMembersBundle/Entity/FamilyMember.php index ca2d4af92..854b4aa58 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Entity/FamilyMember.php +++ b/src/Bundle/ChillFamilyMembersBundle/Entity/FamilyMember.php @@ -1,11 +1,18 @@ configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - - /** - * {@inheritdoc} - */ public function buildForm(FormBuilderInterface $builder, array $options) { - $builder ->add('lastname', TextType::class, [ - 'label' => 'Last name' + 'label' => 'Last name', ]) ->add('firstname', TextType::class, [ - 'label' => 'First name' + 'label' => 'First name', ]) ->add('gender', GenderType::class) ->add('birthdate', ChillDateType::class, [ - 'required' => false + 'required' => false, ]) ->add('link', ChoiceType::class, [ 'choices' => $this->buildChoices($this->configRepository->getLinksLabels()), 'placeholder' => 'Choose a link', - 'label' => 'Relationship' + 'label' => 'Relationship', ]) ->add('maritalStatus', Select2MaritalStatusType::class, [ - 'required' => false - ]) - ; - + 'required' => false, + ]); + if ($this->configRepository->hasProfessionalSituation()) { $builder - ->add('professionnalSituation', ChoiceType::class, [ - 'required' => false, - 'choices' => $this->buildChoices( - $this->configRepository->getProfessionalSituationsLabels() - ) - ]); + ->add('professionnalSituation', ChoiceType::class, [ + 'required' => false, + 'choices' => $this->buildChoices( + $this->configRepository->getProfessionalSituationsLabels() + ), + ]); } - + if ($this->configRepository->hasProfessionalSituation()) { $builder - ->add('familialSituation', ChoiceType::class, [ - 'required' => false, - 'choices' => $this->buildChoices( - $this->configRepository->getFamilialSituationsLabels() - ) - ]); + ->add('familialSituation', ChoiceType::class, [ + 'required' => false, + 'choices' => $this->buildChoices( + $this->configRepository->getFamilialSituationsLabels() + ), + ]); } - + if ($options['show_start_date']) { $builder ->add('startDate', ChillDateType::class, [ - 'label' => 'Arrival date in the family' + 'label' => 'Arrival date in the family', ]); } - + if ($options['show_end_date']) { $builder ->add('endDate', ChillDateType::class, [ 'required' => false, - 'label' => 'Departure date of the family' + 'label' => 'Departure date of the family', ]); } + } - }/** - * {@inheritdoc} - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => FamilyMember::class, 'show_start_date' => true, 'show_end_date' => true, - )); - + ]); + $resolver ->setAllowedTypes('show_start_date', 'boolean') - ->setAllowedTypes('show_end_date', 'boolean') - ; - } - - private function buildChoices($els) - { - $links = $this->configRepository - ->getLinksLabels(); - $choices = []; - - // rewrite labels to filter in language - foreach ($els as $key => $labels) { - $choices[$this->translatableStringHelper->localize($labels)] = $key; - } - - return $choices; + ->setAllowedTypes('show_end_date', 'boolean'); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_amli_familymembersbundle_familymember'; } + private function buildChoices($els) + { + $links = $this->configRepository + ->getLinksLabels(); + $choices = []; + // rewrite labels to filter in language + foreach ($els as $key => $labels) { + $choices[$this->translatableStringHelper->localize($labels)] = $key; + } + + return $choices; + } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Form/FamilyMembersType.php b/src/Bundle/ChillFamilyMembersBundle/Form/FamilyMembersType.php index b8561b633..df99d5ba9 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Form/FamilyMembersType.php +++ b/src/Bundle/ChillFamilyMembersBundle/Form/FamilyMembersType.php @@ -1,18 +1,18 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\FamilyMembersBundle\Form; + +use Chill\MainBundle\Form\Type\ChillCollectionType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; + class FamilyMembersType extends AbstractType { public function configureOptions(OptionsResolver $resolver) @@ -21,15 +21,15 @@ class FamilyMembersType extends AbstractType 'entry_type' => FamilyMemberType::class, 'entry_options' => [ 'show_start_date' => true, - 'show_end_date' => true + 'show_end_date' => true, ], 'allow_add' => true, 'allow_delete' => true, 'button_add_label' => 'Ajouter un membre', - 'button_remove_label' => 'Enlever ce membre' + 'button_remove_label' => 'Enlever ce membre', ]); } - + public function getParent() { return ChillCollectionType::class; diff --git a/src/Bundle/ChillFamilyMembersBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillFamilyMembersBundle/Menu/UserMenuBuilder.php index fb226cf5f..565198894 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillFamilyMembersBundle/Menu/UserMenuBuilder.php @@ -1,61 +1,59 @@ - */ class UserMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( - AuthorizationCheckerInterface $authorizationChecker, + AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator ) { $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person']; - + if ($this->authorizationChecker->isGranted(FamilyMemberVoter::SHOW, $person)) { $menu->addChild( - $this->translator->trans('Family memberships'), [ + $this->translator->trans('Family memberships'), + [ 'route' => 'chill_family_members_family_members_index', - 'routeParameters' => [ 'id' => $person->getId() ], - ]) - ->setExtra('order', 450) - ; + 'routeParameters' => ['id' => $person->getId()], + ] + ) + ->setExtra('order', 450); } } public static function getMenuIds(): array { - return [ 'person' ]; + return ['person']; } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php b/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php index 618128c96..8e1df6e45 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php +++ b/src/Bundle/ChillFamilyMembersBundle/Repository/FamilyMemberRepository.php @@ -1,17 +1,23 @@ findBy([ 'person' => $person ]); + return $this->findBy(['person' => $person]); } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Resources/migrations/Version20180522142023.php b/src/Bundle/ChillFamilyMembersBundle/Resources/migrations/Version20180522142023.php index 90ac49a32..47cf5df6a 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Resources/migrations/Version20180522142023.php +++ b/src/Bundle/ChillFamilyMembersBundle/Resources/migrations/Version20180522142023.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SCHEMA chill_family CASCADE'); + } + + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -25,12 +41,4 @@ final class Version20180522142023 extends AbstractMigration $this->addSql('ALTER TABLE chill_family.family_member ADD CONSTRAINT FK_A61F4A49217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_family.family_member ADD CONSTRAINT FK_A61F4A49D7D03CE3 FOREIGN KEY (maritalStatus_id) REFERENCES chill_person_marital_status (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP SCHEMA chill_family CASCADE'); - - } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php b/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php index 5e218657c..ad61dd94e 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php +++ b/src/Bundle/ChillFamilyMembersBundle/Security/Voter/FamilyMemberVoter.php @@ -1,79 +1,81 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\AMLI\FamilyMembersBundle\Security\Voter; + +use Chill\AMLI\FamilyMembersBundle\Entity\FamilyMember; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; +use Chill\PersonBundle\Entity\Person; +use Symfony\Component\Security\Core\Role\Role; + +use function in_array; + class FamilyMemberVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_CREATE'; - const DELETE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_DELETE'; - const UPDATE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_UPDATE'; - const SHOW = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_SHOW'; - - const ROLES = [ + public const CREATE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_CREATE'; + + public const DELETE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_DELETE'; + + public const ROLES = [ self::CREATE, self::DELETE, self::SHOW, - self::UPDATE + self::UPDATE, ]; - + + public const SHOW = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_SHOW'; + + public const UPDATE = 'CHILL_FAMILY_MEMBERS_FAMILY_MEMBERS_UPDATE'; + /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + public function __construct(AuthorizationHelper $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } - - protected function supports($attribute, $subject) - { - return (\in_array($attribute, self::ROLES) && $subject instanceof FamilyMember) - or - ($subject instanceof Person && \in_array($attribute, [ self::SHOW, self::CREATE ])); - } - - protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token) - { - $user = $token->getUser(); - - if (FALSE === $user instanceof User) { - return false; - } - - return $this->authorizationHelper - ->userHasAccess($user, $subject, new Role($attribute)); - } - public function getRoles() { return self::ROLES; - } - + } + public function getRolesWithHierarchy(): array { - return [ 'Family Members' => self::ROLES ]; - } - + return ['Family Members' => self::ROLES]; + } + public function getRolesWithoutScope() { return self::ROLES; } + protected function supports($attribute, $subject) + { + return (in_array($attribute, self::ROLES) && $subject instanceof FamilyMember) + or ($subject instanceof Person && in_array($attribute, [self::SHOW, self::CREATE])); + } + + protected function voteOnAttribute($attribute, $subject, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token) + { + $user = $token->getUser(); + + if (false === $user instanceof User) { + return false; + } + + return $this->authorizationHelper + ->userHasAccess($user, $subject, new Role($attribute)); + } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Templating/Twig.php b/src/Bundle/ChillFamilyMembersBundle/Templating/Twig.php index e02d7e024..f10c2ab66 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Templating/Twig.php +++ b/src/Bundle/ChillFamilyMembersBundle/Templating/Twig.php @@ -1,102 +1,97 @@ - */ class Twig extends AbstractExtension { /** - * * @var ConfigRepository */ protected $configRepository; - + /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct( - ConfigRepository $configRepository, + ConfigRepository $configRepository, TranslatableStringHelper $translatableStringHelper ) { $this->configRepository = $configRepository; $this->translatableStringHelper = $translatableStringHelper; } - + public function displayFamilialSituation($situation) + { + if (null === $situation) { + return null; + } + + return $this->translatableStringHelper->localize( + $this->configRepository->getFamilialSituationsLabels()[$situation] + ); + } + + public function displayLink($link) + { + if (null === $link) { + return null; + } + + return $this->translatableStringHelper->localize( + $this->configRepository->getLinksLabels()[$link] + ); + } + + public function displayProfessionalSituation($situation) + { + if (null === $situation) { + return null; + } + + return $this->translatableStringHelper->localize( + $this->configRepository->getProfessionalSituationsLabels()[$situation] + ); + } + public function getFilters() { return [ - new TwigFilter('chill_family_member_link_display', [ $this, 'displayLink' ], [ 'is_safe' => [ 'html' ]]), - new TwigFilter('chill_family_member_professional_situation_display', [ $this, 'displayProfessionalSituation' ], [ 'is_safe' => [ 'html' ]]), - new TwigFilter('chill_family_member_familial_situation_display', [ $this, 'displayFamilialSituation' ], [ 'is_safe' => [ 'html' ]]), - + new TwigFilter('chill_family_member_link_display', [$this, 'displayLink'], ['is_safe' => ['html']]), + new TwigFilter('chill_family_member_professional_situation_display', [$this, 'displayProfessionalSituation'], ['is_safe' => ['html']]), + new TwigFilter('chill_family_member_familial_situation_display', [$this, 'displayFamilialSituation'], ['is_safe' => ['html']]), ]; } - + public function getFunctions() { return [ - new TwigFunction('chill_family_members_has_professionnal_situation', [ $this, 'hasProfessionnalSituation' ]), - new TwigFunction('chill_family_members_has_familial_situation', [ $this, 'hasFamilialSituation' ]), - + new TwigFunction('chill_family_members_has_professionnal_situation', [$this, 'hasProfessionnalSituation']), + new TwigFunction('chill_family_members_has_familial_situation', [$this, 'hasFamilialSituation']), ]; } - - public function displayLink($link) - { - if (NULL === $link) { - return null; - } - - return $this->translatableStringHelper->localize( - $this->configRepository->getLinksLabels()[$link] - ); - } - - public function displayProfessionalSituation($situation) - { - if (NULL === $situation) { - return null; - } - - return $this->translatableStringHelper->localize( - $this->configRepository->getProfessionalSituationsLabels()[$situation] - ); - } - - public function hasProfessionnalSituation() - { - return $this->configRepository->hasProfessionalSituation(); - } - - public function displayFamilialSituation($situation) - { - if (NULL === $situation) { - return null; - } - - return $this->translatableStringHelper->localize( - $this->configRepository->getFamilialSituationsLabels()[$situation] - ); - } - + public function hasFamilialSituation() { return $this->configRepository->hasFamilialSituation(); } + + public function hasProfessionnalSituation() + { + return $this->configRepository->hasProfessionalSituation(); + } } diff --git a/src/Bundle/ChillFamilyMembersBundle/Tests/Controller/FamilyMemberControllerTest.php b/src/Bundle/ChillFamilyMembersBundle/Tests/Controller/FamilyMemberControllerTest.php index 01e8d52df..6baa62bc1 100644 --- a/src/Bundle/ChillFamilyMembersBundle/Tests/Controller/FamilyMemberControllerTest.php +++ b/src/Bundle/ChillFamilyMembersBundle/Tests/Controller/FamilyMemberControllerTest.php @@ -1,11 +1,29 @@ request('GET', '/edit'); + } + public function testIndex() { $client = static::createClient(); @@ -19,12 +37,4 @@ class FamilyMemberControllerTest extends WebTestCase $crawler = $client->request('GET', '/new'); } - - public function testEdit() - { - $client = static::createClient(); - - $crawler = $client->request('GET', '/edit'); - } - } diff --git a/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php b/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php index d8a46837c..c76f7e8e4 100644 --- a/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php +++ b/src/Bundle/ChillMainBundle/CRUD/CompilerPass/CRUDControllerCompilerPass.php @@ -1,32 +1,18 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\CRUD\CompilerPass; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Reference; -use Chill\MainBundle\Routing\MenuComposer; -use Symfony\Component\DependencyInjection\Definition; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\CRUD\CompilerPass; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; + class CRUDControllerCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) @@ -44,13 +30,13 @@ class CRUDControllerCompilerPass implements CompilerPassInterface } /** - * Add a controller for each definition, and add a methodCall to inject crud configuration to controller + * Add a controller for each definition, and add a methodCall to inject crud configuration to controller. */ private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void { $controllerClass = $crudEntry['controller']; - $controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller'; + $controllerServiceName = 'cs' . $apiOrCrud . '_' . $crudEntry['name'] . '_controller'; if ($container->hasDefinition($controllerClass)) { $controller = $container->getDefinition($controllerClass); @@ -62,16 +48,16 @@ class CRUDControllerCompilerPass implements CompilerPassInterface } $controller->addTag('controller.service_arguments'); - if (FALSE === $alreadyDefined) { + + if (false === $alreadyDefined) { $controller->setAutoconfigured(true); $controller->setPublic(true); } - $param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name']; + $param = 'chill_main_' . $apiOrCrud . '_config_' . $crudEntry['name']; $container->setParameter($param, $crudEntry); - $controller->addMethodCall('setCrudConfig', ['%'.$param.'%']); + $controller->addMethodCall('setCrudConfig', ['%' . $param . '%']); $container->setDefinition($controllerServiceName, $controller); } - } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php index 5cc055f26..9d5780087 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/AbstractCRUDController.php @@ -1,29 +1,120 @@ crudConfig = $config; + } + + /** + * Build the base query for listing all entities. + * + * This method is used internally by `countEntities` `queryEntities` + * + * This base query does not contains any `WHERE` or `SELECT` clauses. You + * can add some by using the method `customizeQuery`. + * + * The alias for the entity is "e". + * + * @return QueryBuilder + */ + protected function buildQueryEntities(string $action, Request $request) + { + $qb = $this->getDoctrine()->getManager() + ->createQueryBuilder() + ->select('e') + ->from($this->getEntityClass(), 'e'); + + $this->customizeQuery($action, $request, $qb); + + return $qb; + } + + /** + * check the acl. Called by every action. + * + * By default, check the role given by `getRoleFor` for the value given in + * $entity. + * + * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException + * if not accessible. + * + * @param mixed|null $entity + * + * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException + */ + protected function checkACL(string $action, Request $request, string $_format, $entity = null) + { + $this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity); + } + + /** + * Count the number of entities. + * + * By default, count all entities. You can customize the query by + * using the method `customizeQuery`. + * + * @param mixed $_format + */ + protected function countEntities(string $action, Request $request, $_format): int + { + return $this->buildQueryEntities($action, $request) + ->select('COUNT(e)') + ->getQuery() + ->getSingleScalarResult(); + } + + protected function customizeQuery(string $action, Request $request, $query): void + { + } + + protected function getActionConfig(string $action) + { + return $this->crudConfig['actions'][$action]; + } + + /** + * @return string the crud name + */ + protected function getCrudName(): string + { + return $this->crudConfig['name']; + } + + /** + * get the instance of the entity with the given id. + * * @param string $id + * @param mixed $action + * * @return object */ protected function getEntity($action, $id, Request $request): ?object @@ -34,141 +125,34 @@ class AbstractCRUDController extends AbstractController } /** - * Count the number of entities + * Get the complete FQDN of the class. * - * By default, count all entities. You can customize the query by - * using the method `customizeQuery`. - * - * @param string $action - * @param Request $request - * @return int - */ - protected function countEntities(string $action, Request $request, $_format): int - { - return $this->buildQueryEntities($action, $request) - ->select('COUNT(e)') - ->getQuery() - ->getSingleScalarResult() - ; - } - - /** - * Query the entity. - * - * By default, get all entities. You can customize the query by using the - * method `customizeQuery`. - * - * The method `orderEntity` is called internally to order entities. - * - * It returns, by default, a query builder. - * - */ - protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator) - { - $query = $this->buildQueryEntities($action, $request) - ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) - ->setMaxResults($paginator->getItemsPerPage()); - - // allow to order queries and return the new query - return $this->orderQuery($action, $query, $request, $paginator, $_format); - } - - /** - * Add ordering fields in the query build by self::queryEntities - * - */ - protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) - { - return $query; - } - - /** - * Build the base query for listing all entities. - * - * This method is used internally by `countEntities` `queryEntities` - * - * This base query does not contains any `WHERE` or `SELECT` clauses. You - * can add some by using the method `customizeQuery`. - * - * The alias for the entity is "e". - * - * @param string $action - * @param Request $request - * @return QueryBuilder - */ - protected function buildQueryEntities(string $action, Request $request) - { - $qb = $this->getDoctrine()->getManager() - ->createQueryBuilder() - ->select('e') - ->from($this->getEntityClass(), 'e') - ; - - $this->customizeQuery($action, $request, $qb); - - return $qb; - } - - protected function customizeQuery(string $action, Request $request, $query): void {} - - /** - * Get the result of the query - */ - protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query) - { - return $query->getQuery()->getResult(); - } - - protected function onPreIndex(string $action, Request $request, string $_format): ?Response - { - return null; - } - - /** - * method used by indexAction - */ - protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response - { - return null; - } - - /** - * method used by indexAction - */ - protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response - { - return null; - } - - /** - * method used by indexAction - */ - protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response - { - return null; - } - - - /** - * Get the complete FQDN of the class - * * @return string the complete fqdn of the class */ protected function getEntityClass(): string { return $this->crudConfig['class']; } - - /** - * called on post fetch entity - */ - protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response + + protected function getPaginatorFactory(): PaginatorFactory { - return null; + return $this->container->get('chill_main.paginator_factory'); } /** - * Called on post check ACL + * Get the result of the query. + * + * @param mixed $query + */ + protected function getQueryResult(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query) + { + return $query->getQuery()->getResult(); + } + + /** + * Called on post check ACL. + * + * @param mixed $entity */ protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response { @@ -176,50 +160,77 @@ class AbstractCRUDController extends AbstractController } /** - * check the acl. Called by every action. - * - * By default, check the role given by `getRoleFor` for the value given in - * $entity. - * - * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - * if not accessible. - * - * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - */ - protected function checkACL(string $action, Request $request, string $_format, $entity = null) - { - $this->denyAccessUnlessGranted($this->getRoleFor($action, $request, $entity, $_format), $entity); - } - - /** - * - * @return string the crud name - */ - protected function getCrudName(): string - { - return $this->crudConfig['name']; - } - - protected function getActionConfig(string $action) - { - return $this->crudConfig['actions'][$action]; - } - - /** - * Set the crud configuration + * called on post fetch entity. * - * Used by the container to inject configuration for this crud. + * @param mixed $entity + * @param mixed $_format */ - public function setCrudConfig(array $config): void + protected function onPostFetchEntity(string $action, Request $request, $entity, $_format): ?Response { - $this->crudConfig = $config; + return null; } /** - * @return PaginatorFactory + * method used by indexAction. + * + * @param mixed $query */ - protected function getPaginatorFactory(): PaginatorFactory + protected function onPostIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $query): ?Response { - return $this->container->get('chill_main.paginator_factory'); + return null; + } + + /** + * method used by indexAction. + * + * @param mixed $entities + */ + protected function onPostIndexFetchQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator, $entities): ?Response + { + return null; + } + + protected function onPreIndex(string $action, Request $request, string $_format): ?Response + { + return null; + } + + /** + * method used by indexAction. + */ + protected function onPreIndexBuildQuery(string $action, Request $request, string $_format, int $totalItems, PaginatorInterface $paginator): ?Response + { + return null; + } + + /** + * Add ordering fields in the query build by self::queryEntities. + * + * @param mixed $query + * @param mixed $_format + */ + protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator, $_format) + { + return $query; + } + + /** + * Query the entity. + * + * By default, get all entities. You can customize the query by using the + * method `customizeQuery`. + * + * The method `orderEntity` is called internally to order entities. + * + * It returns, by default, a query builder. + */ + protected function queryEntities(string $action, Request $request, string $_format, PaginatorInterface $paginator) + { + $query = $this->buildQueryEntities($action, $request) + ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) + ->setMaxResults($paginator->getItemsPerPage()); + + // allow to order queries and return the new query + return $this->orderQuery($action, $query, $request, $paginator, $_format); } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php index 7643db0e9..e288366e2 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/ApiController.php @@ -1,79 +1,28 @@ getEntity($action, $id, $request, $_format); - - $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); - - if ($postFetch instanceof Response) { - return $postFetch; - } - - if (NULL === $entity) { - throw $this->createNotFoundException(sprintf("The %s with id %s " - . "is not found", $this->getCrudName(), $id)); - } - - $response = $this->checkACL($action, $request, $_format, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onPostCheckACL($action, $request, $_format, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onBeforeSerialize($action, $request, $_format, $entity); - if ($response instanceof Response) { - return $response; - } - - if ($_format === 'json') { - $context = $this->getContextForSerialization($action, $request, $_format, $entity); - - return $this->json($entity, Response::HTTP_OK, [], $context); - } else { - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This format is not implemented"); - } - } - - public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response - { - return null; - } - - /** - * Base method for handling api action + * Base method for handling api action. + * + * @param mixed $id + * @param mixed $_format * * @return void */ @@ -83,13 +32,14 @@ class ApiController extends AbstractCRUDController case Request::METHOD_GET: case REQUEST::METHOD_HEAD: return $this->entityGet('_entity', $request, $id, $_format); + default: - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This method is not implemented"); + throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented'); } } /** - * Base action for indexing entities + * Base action for indexing entities. */ public function indexApi(Request $request, string $_format) { @@ -97,18 +47,118 @@ class ApiController extends AbstractCRUDController case Request::METHOD_GET: case REQUEST::METHOD_HEAD: return $this->indexApiAction('_index', $request, $_format); + default: - throw $this->createNotFoundException("This method is not supported"); + throw $this->createNotFoundException('This method is not supported'); } } + public function onBeforeSerialize(string $action, Request $request, $_format, $entity): ?Response + { + return null; + } + + /** + * The view action. + * + * Some steps may be overriden during this process of rendering: + * + * This method: + * + * 1. fetch the entity, using `getEntity` + * 2. launch `onPostFetchEntity`. If postfetch is an instance of Response, + * this response is returned. + * 2. throw an HttpNotFoundException if entity is null + * 3. check ACL using `checkACL` ; + * 4. launch `onPostCheckACL`. If the result is an instance of Response, + * this response is returned ; + * 5. Serialize the entity and return the result. The serialization context is given by `getSerializationContext` + * + * @param mixed $id + * @param mixed $_format + */ + protected function entityGet(string $action, Request $request, $id, $_format = 'html'): Response + { + $entity = $this->getEntity($action, $id, $request, $_format); + + $postFetch = $this->onPostFetchEntity($action, $request, $entity, $_format); + + if ($postFetch instanceof Response) { + return $postFetch; + } + + if (null === $entity) { + throw $this->createNotFoundException(sprintf('The %s with id %s ' + . 'is not found', $this->getCrudName(), $id)); + } + + $response = $this->checkACL($action, $request, $_format, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $_format, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onBeforeSerialize($action, $request, $_format, $entity); + + if ($response instanceof Response) { + return $response; + } + + if ('json' === $_format) { + $context = $this->getContextForSerialization($action, $request, $_format, $entity); + + return $this->json($entity, Response::HTTP_OK, [], $context); + } + + throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented'); + } + + protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array + { + return []; + } + + /** + * get the role given from the config. + * + * @param mixed $entity + * @param mixed $_format + */ + protected function getRoleFor(string $action, Request $request, $entity, $_format): string + { + $actionConfig = $this->getActionConfig($action); + + if (null !== $actionConfig['roles'][$request->getMethod()]) { + return $actionConfig['roles'][$request->getMethod()]; + } + + if ($this->crudConfig['base_role']) { + return $this->crudConfig['base_role']; + } + + throw new RuntimeException(sprintf('the config does not have any role for the ' . + 'method %s nor a global role for the whole action. Add those to your ' . + 'configuration or override the required method', $request->getMethod())); + } + + protected function getSerializer(): SerializerInterface + { + return $this->get('serializer'); + } + /** * Build an index page. - * + * * Some steps may be overriden during this process of rendering. - * + * * This method: - * + * * 1. Launch `onPreIndex` * x. check acl. If it does return a response instance, return it * x. launch `onPostCheckACL`. If it does return a response instance, return it @@ -119,63 +169,84 @@ class ApiController extends AbstractCRUDController * x. fetch the results, using `getQueryResult` * x. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it * 4. Serialize the entities in a Collection, using `SerializeCollection` - * + * * @param string $action - * @param Request $request + * @param mixed $_format + * * @return type */ protected function indexApiAction($action, Request $request, $_format) { $this->onPreIndex($action, $request, $_format); - + $response = $this->checkACL($action, $request, $_format); + if ($response instanceof Response) { return $response; } - + if (!isset($entity)) { $entity = ''; } - + $response = $this->onPostCheckACL($action, $request, $_format, $entity); + if ($response instanceof Response) { return $response; } - + $totalItems = $this->countEntities($action, $request, $_format); $paginator = $this->getPaginatorFactory()->create($totalItems); - - $response = $this->onPreIndexBuildQuery($action, $request, $_format, $totalItems, - $paginator); - + + $response = $this->onPreIndexBuildQuery( + $action, + $request, + $_format, + $totalItems, + $paginator + ); + if ($response instanceof Response) { return $response; } - + $query = $this->queryEntities($action, $request, $_format, $paginator); - - $response = $this->onPostIndexBuildQuery($action, $request, $_format, $totalItems, - $paginator, $query); - + + $response = $this->onPostIndexBuildQuery( + $action, + $request, + $_format, + $totalItems, + $paginator, + $query + ); + if ($response instanceof Response) { return $response; } - + $entities = $this->getQueryResult($action, $request, $_format, $totalItems, $paginator, $query); - - $response = $this->onPostIndexFetchQuery($action, $request, $_format, $totalItems, - $paginator, $entities); - + + $response = $this->onPostIndexFetchQuery( + $action, + $request, + $_format, + $totalItems, + $paginator, + $entities + ); + if ($response instanceof Response) { return $response; } - - return $this->serializeCollection($action, $request, $_format, $paginator, $entities); + + return $this->serializeCollection($action, $request, $_format, $paginator, $entities); } - + /** - * Serialize collections + * Serialize collections. * + * @param mixed $entities */ protected function serializeCollection(string $action, Request $request, string $_format, PaginatorInterface $paginator, $entities): Response { @@ -185,36 +256,4 @@ class ApiController extends AbstractCRUDController return $this->json($model, Response::HTTP_OK, [], $context); } - - - protected function getContextForSerialization(string $action, Request $request, string $_format, $entity): array - { - return []; - } - - /** - * get the role given from the config. - */ - protected function getRoleFor(string $action, Request $request, $entity, $_format): string - { - $actionConfig = $this->getActionConfig($action); - - if (NULL !== $actionConfig['roles'][$request->getMethod()]) { - return $actionConfig['roles'][$request->getMethod()]; - } - - if ($this->crudConfig['base_role']) { - return $this->crudConfig['base_role']; - } - - throw new \RuntimeException(sprintf("the config does not have any role for the ". - "method %s nor a global role for the whole action. Add those to your ". - "configuration or override the required method", $request->getMethod())); - - } - - protected function getSerializer(): SerializerInterface - { - return $this->get('serializer'); - } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php index 8338af8c6..a37218822 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php +++ b/src/Bundle/ChillMainBundle/CRUD/Controller/CRUDController.php @@ -1,1199 +1,92 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\CRUD\Controller; -use Doctrine\ORM\QueryBuilder; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Form\FormInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Chill\MainBundle\CRUD\Resolver\Resolver; use Chill\MainBundle\CRUD\Form\CRUDDeleteEntityForm; +use Chill\MainBundle\CRUD\Resolver\Resolver; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Pagination\PaginatorInterface; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +use function array_key_exists; +use function array_merge; /** - * Class CRUDController - * - * @package Chill\MainBundle\CRUD\Controller + * Class CRUDController. */ class CRUDController extends AbstractController { - /** - * The crud configuration + * The crud configuration. * * This configuration si defined by `chill_main['crud']`. * * @var array */ protected $crudConfig; - - /** - * @param array $config - */ - public function setCrudConfig(array $config) - { - $this->crudConfig = $config; - } - + /** * @param $parameter + * * @return Response */ public function CRUD($parameter) { return new Response($parameter); } - + /** - * @param Request $request * @param $id - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse */ public function delete(Request $request, $id) { return $this->deleteAction('delete', $request, $id); } - + /** - * @param string $action - * @param Request $request - * @param $id - * @param null $formClass - * @return null|\Symfony\Component\HttpFoundation\RedirectResponse|Response|void - */ - protected function deleteAction(string $action, Request $request, $id, $formClass = null) - { - $this->onPreDelete($action, $request, $id); - - $entity = $this->getEntity($action, $id, $request); - - $postFetch = $this->onPostFetchEntity($action, $request, $entity); - - if ($postFetch instanceof Response) { - return $postFetch; - } - - if (NULL === $entity) { - throw $this->createNotFoundException(sprintf("The %s with id %s " - . "is not found"), $this->getCrudName(), $id); - } - - $response = $this->checkACL($action, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - $form = $this->createFormFor($action, $entity, $formClass); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->onFormValid($entity, $form, $request); - $em = $this->getDoctrine()->getManager(); - - $this->onPreRemove($action, $entity, $form, $request); - $this->removeEntity($action, $entity, $form, $request); - $this->onPostRemove($action, $entity, $form, $request); - - $this->onPreFlush($action, $entity, $form, $request); - $em->flush(); - $this->onPostFlush($action, $entity, $form, $request); - - $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); - - $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); - - if ($result instanceof Response) { - return $result; - } - - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]); - - } elseif ($form->isSubmitted()) { - $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); - } - - $defaultTemplateParameters = [ - 'form' => $form->createView(), - 'entity' => $entity, - 'crud_name' => $this->getCrudName() - ]; - - return $this->render( - $this->getTemplateFor($action, $entity, $request), - $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) - ); - } - - /** - * @param string $action - * @param Request $request - */ - protected function onPreDelete(string $action, Request $request) {} - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPreRemove(string $action, $entity, FormInterface $form, Request $request) {} - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPostRemove(string $action, $entity, FormInterface $form, Request $request) {} - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function removeEntity(string $action, $entity, FormInterface $form, Request $request) - { - $this->getDoctrine() - ->getManager() - ->remove($entity); - } - - /** - * Base method called by index action. - * - * @param Request $request - * @return type - */ - public function index(Request $request) - { - return $this->indexEntityAction('index', $request); - } - - /** - * Build an index page. - * - * Some steps may be overriden during this process of rendering. - * - * This method: - * - * 1. Launch `onPreIndex` - * x. check acl. If it does return a response instance, return it - * x. launch `onPostCheckACL`. If it does return a response instance, return it - * 1. count the items, using `countEntities` - * 2. build a paginator element from the the number of entities ; - * 3. Launch `onPreIndexQuery`. If it does return a response instance, return it - * 3. build a query, using `queryEntities` - * x. fetch the results, using `getQueryResult` - * x. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it - * 4. create default parameters: - * - * The default parameters are: - * - * * entities: the list en entities ; - * * crud_name: the name of the crud ; - * * paginator: a paginator element ; - * 5. Launch rendering, the parameter is fetch using `getTemplateFor` - * The parameters may be personnalized using `generateTemplateParameter`. - * - * @param string $action - * @param Request $request - * @return type - */ - protected function indexEntityAction($action, Request $request) - { - $this->onPreIndex($action, $request); - - $response = $this->checkACL($action, null); - if ($response instanceof Response) { - return $response; - } - - if (!isset($entity)) { - $entity = ''; - } - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - $totalItems = $this->countEntities($action, $request); - $paginator = $this->getPaginatorFactory()->create($totalItems); - - $response = $this->onPreIndexBuildQuery($action, $request, $totalItems, - $paginator); - - if ($response instanceof Response) { - return $response; - } - - $query = $this->queryEntities($action, $request, $paginator); - - $response = $this->onPostIndexBuildQuery($action, $request, $totalItems, - $paginator, $query); - - if ($response instanceof Response) { - return $response; - } - - $entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $query); - - $response = $this->onPostIndexFetchQuery($action, $request, $totalItems, - $paginator, $entities); - - if ($response instanceof Response) { - return $response; - } - - $defaultTemplateParameters = [ - 'entities' => $entities, - 'crud_name' => $this->getCrudName(), - 'paginator' => $paginator - ]; - - return $this->render( - $this->getTemplateFor($action, $entities, $request), - $this->generateTemplateParameter($action, $entities, $request, $defaultTemplateParameters) - ); - } - - /** - * @param string $action - * @param Request $request - */ - protected function onPreIndex(string $action, Request $request) { } - - /** - * method used by indexAction - * - * @param string $action - * @param Request $request - * @param int $totalItems - * @param PaginatorInterface $paginator - */ - protected function onPreIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator) { } - - /** - * method used by indexAction - * - * @param string $action - * @param Request $request - * @param int $totalItems - * @param PaginatorInterface $paginator - * @param mixed $query - */ - protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) { } - - /** - * method used by indexAction - * - * @param string $action - * @param Request $request - * @param int $totalItems - * @param PaginatorInterface $paginator - * @param mixed $entities - */ - protected function onPostIndexFetchQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $entities) { } - - /** - * Build the base query for listing all entities, normally use in a listing - * page. - * - * This base query does not contains any `WHERE` or `SELECT` clauses. Those - * are added by other methods, like `queryEntities` and `countQueries`. - * - * @param string $action - * @param Request $request - * @return QueryBuilder - */ - protected function buildQueryEntities(string $action, Request $request) - { - return $this->getDoctrine()->getManager() - ->createQueryBuilder() - ->select('e') - ->from($this->getEntityClass(), 'e') - ; - } - - /** - * Query the entity. - * - * By default, get all entities. - * - * The method `orderEntity` is called internally to order entities. - * - * It returns, by default, a query builder. - * - * @param string $action - * @param Request $request - * @param PaginatorInterface $paginator - * @return type - */ - protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator) - { - $query = $this->buildQueryEntities($action, $request) - ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) - ->setMaxResults($paginator->getItemsPerPage()); - - // allow to order queries and return the new query - return $this->orderQuery($action, $query, $request, $paginator); - } - - - /** - * Add ordering fields in the query build by self::queryEntities - * - * @param string $action - * @param QueryBuilder|mixed $query by default, an instance of QueryBuilder - * @param Request $request - * @param PaginatorInterface $paginator - * @return QueryBuilder|mixed - */ - protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) - { - return $query; - } - - /** - * Get the result of the query - * - * @param string $action - * @param Request $request - * @param int $totalItems - * @param PaginatorInterface $paginator - * @param mixed $query - * @return mixed - */ - protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) - { - return $query->getQuery()->getResult(); - } - - /** - * Count the number of entities - * - * @param string $action - * @param Request $request - * @return int - */ - protected function countEntities(string $action, Request $request): int - { - return $this->buildQueryEntities($action, $request) - ->select('COUNT(e)') - ->getQuery() - ->getSingleScalarResult() - ; - } - - /** - * BAse method for edit action - * + * BAse method for edit action. + * * IMplemented by the method formEditAction, with action as 'edit' - * - * @param Request $request + * * @param mixed $id - * @return Response */ public function edit(Request $request, $id): Response { return $this->formEditAction('edit', $request, $id); } - - /** - * Base method for new action - * - * Implemented by the method formNewAction, with action as 'new' - * - * @param Request $request - * @return Response - */ - public function new(Request $request): Response - { - return $this->formCreateAction('new', $request); - } - - /** - * Base method for the view action. - * - * Implemented by the method viewAction, with action as 'view' - * - * @param Request $request - * @param mixed $id - * @return Response - */ - public function view(Request $request, $id): Response - { - return $this->viewAction('view', $request, $id); - } - - /** - * The view action. - * - * Some steps may be overriden during this process of rendering: - * - * This method: - * - * 1. fetch the entity, using `getEntity` - * 2. launch `onPostFetchEntity`. If postfetch is an instance of Response, - * this response is returned. - * 2. throw an HttpNotFoundException if entity is null - * 3. check ACL using `checkACL` ; - * 4. launch `onPostCheckACL`. If the result is an instance of Response, - * this response is returned ; - * 5. generate default template parameters: - * - * * `entity`: the fetched entity ; - * * `crud_name`: the crud name - * 6. Launch rendering, the parameter is fetch using `getTemplateFor` - * The parameters may be personnalized using `generateTemplateParameter`. - * - * @param string $action - * @param Request $request - * @param mixed $id - * @return Response - */ - protected function viewAction(string $action, Request $request, $id, $_format = 'html'): Response - { - $entity = $this->getEntity($action, $id, $request); - - $postFetch = $this->onPostFetchEntity($action, $request, $entity); - - if ($postFetch instanceof Response) { - return $postFetch; - } - - if (NULL === $entity) { - throw $this->createNotFoundException(sprintf("The %s with id %s " - . "is not found", $this->getCrudName(), $id)); - } - - $response = $this->checkACL($action, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - if ($_format === 'html') { - $defaultTemplateParameters = [ - 'entity' => $entity, - 'crud_name' => $this->getCrudName() - ]; - - return $this->render( - $this->getTemplateFor($action, $entity, $request), - $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) - ); - } elseif ($_format === 'json') { - $context = $this->getContextForSerialization($action, $request, $entity, $_format); - - return $this->json($entity, Response::HTTP_OK, [], $context); - } else { - throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException("This format is not implemented"); - } - - } /** - * Get the context for the serialization + * Get the context for the serialization. + * + * @param mixed $entity */ public function getContextForSerialization(string $action, Request $request, $entity, string $_format): array { return []; } - - - /** - * The edit action. - * - * Some steps may be overriden during this process of rendering: - * - * This method: - * - * 1. fetch the entity, using `getEntity` - * 2. launch `onPostFetchEntity`. If postfetch is an instance of Response, - * this response is returned. - * 2. throw an HttpNotFoundException if entity is null - * 3. check ACL using `checkACL` ; - * 4. launch `onPostCheckACL`. If the result is an instance of Response, - * this response is returned ; - * 5. generate a form using `createFormFor`, and handle request on this form; - * - * If the form is valid, the entity is stored and flushed, and a redirection - * is returned. - * - * In this case, those hooks are available: - * - * * onFormValid - * * onPreFlush - * * onPostFlush - * * onBeforeRedirectAfterSubmission. If this method return an instance of - * Response, this response is returned. - * - * 5. generate default template parameters: - * - * * `entity`: the fetched entity ; - * * `crud_name`: the crud name ; - * * `form`: the formview instance. - * - * 6. Launch rendering, the parameter is fetch using `getTemplateFor` - * The parameters may be personnalized using `generateTemplateParameter`. - * - * @param string $action - * @param Request $request - * @param mixed $id - * @param string $formClass - * @param array $formOptions - * @return Response - * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException - */ - protected function formEditAction(string $action, Request $request, $id, string $formClass = null, array $formOptions = []): Response - { - $entity = $this->getEntity($action, $id, $request); - - if (NULL === $entity) { - throw $this->createNotFoundException(sprintf("The %s with id %s " - . "is not found"), $this->getCrudName(), $id); - } - - $response = $this->checkACL($action, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - $form = $this->createFormFor($action, $entity, $formClass, $formOptions); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->onFormValid($entity, $form, $request); - $em = $this->getDoctrine()->getManager(); - - $this->onPreFlush($action, $entity, $form, $request); - $em->flush(); - $this->onPostFlush($action, $entity, $form, $request); - - $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); - - $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); - - if ($result instanceof Response) { - return $result; - } - - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index'); - - } elseif ($form->isSubmitted()) { - $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); - } - - $defaultTemplateParameters = [ - 'form' => $form->createView(), - 'entity' => $entity, - 'crud_name' => $this->getCrudName() - ]; - - return $this->render( - $this->getTemplateFor($action, $entity, $request), - $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) - ); - } - - /** - * The new (or creation) action. - * - * Some steps may be overriden during this process of rendering: - * - * This method: - * - * 1. Create or duplicate an entity: - * - * If the `duplicate` parameter is present, the entity is duplicated - * using the `duplicate` method. - * - * If not, the entity is created using the `create` method. - * 3. check ACL using `checkACL` ; - * 4. launch `onPostCheckACL`. If the result is an instance of Response, - * this response is returned ; - * 5. generate a form using `createFormFor`, and handle request on this form; - * - * If the form is valid, the entity is stored and flushed, and a redirection - * is returned. - * - * In this case, those hooks are available: - * - * * onFormValid - * * onPreFlush - * * onPostFlush - * * onBeforeRedirectAfterSubmission. If this method return an instance of - * Response, this response is returned. - * - * 5. generate default template parameters: - * - * * `entity`: the fetched entity ; - * * `crud_name`: the crud name ; - * * `form`: the formview instance. - * - * 6. Launch rendering, the parameter is fetch using `getTemplateFor` - * The parameters may be personnalized using `generateTemplateParameter`. - * - * @param string $action - * @param Request $request - * @param type $formClass - * @return Response - */ - protected function formCreateAction(string $action, Request $request, $formClass = null): Response - { - if ($request->query->has('duplicate')) { - $entity = $this->duplicateEntity($action, $request); - } else { - $entity = $this->createEntity($action, $request); - } - - $response = $this->checkACL($action, $entity); - if ($response instanceof Response) { - return $response; - } - - $response = $this->onPostCheckACL($action, $request, $entity); - if ($response instanceof Response) { - return $response; - } - - $form = $this->createFormFor($action, $entity, $formClass); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $this->onFormValid($entity, $form, $request); - $em = $this->getDoctrine()->getManager(); - - $this->onPrePersist($action, $entity, $form, $request); - $em->persist($entity); - $this->onPostPersist($action, $entity, $form, $request); - - $this->onPreFlush($action, $entity, $form, $request); - $em->flush(); - $this->onPostFlush($action, $entity, $form, $request); - $this->getPaginatorFactory(); - $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); - - $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); - - if ($result instanceof Response) { - return $result; - } - - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', ['id' => $entity->getId()]); - - } elseif ($form->isSubmitted()) { - $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); - } - - $defaultTemplateParameters = [ - 'form' => $form->createView(), - 'entity' => $entity, - 'crud_name' => $this->getCrudName() - ]; - - return $this->render( - $this->getTemplateFor($action, $entity, $request), - $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) - ); - } - - /** - * get the instance of the entity with the given id - * - * @param string $id - * @return object - */ - protected function getEntity($action, $id, Request $request): ?object - { - return $this->getDoctrine() - ->getRepository($this->getEntityClass()) - ->find($id); - } - - /** - * Duplicate an entity - * - * @param string $action - * @param Request $request - * @return mixed - */ - protected function duplicateEntity(string $action, Request $request) - { - $id = $request->query->get('duplicate_id', 0); - $originalEntity = $this->getEntity($action, $id, $request); - - $this->getDoctrine()->getManager() - ->detach($originalEntity); - - return $originalEntity; - } - - /** - * - * @return string the complete fqdn of the class - */ - protected function getEntityClass(): string - { - return $this->crudConfig['class']; - } - - /** - * - * @return string the crud name - */ - protected function getCrudName(): string - { - return $this->crudConfig['name']; - } - - /** - * check the acl. Called by every action. - * - * By default, check the role given by `getRoleFor` for the value given in - * $entity. - * - * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - * if not accessible. - * - * @param string $action - * @param mixed $entity - * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException - */ - protected function checkACL(string $action, $entity) - { - $this->denyAccessUnlessGranted($this->getRoleFor($action), $entity); - } - - /** - * get the role given from the config. - * - * @param string $action - * @return string - */ - protected function getRoleFor($action) - { - if (\array_key_exists('role', $this->getActionConfig($action))) { - return $this->getActionConfig($action)['role']; - } - - return $this->buildDefaultRole($action); - } - - /** - * build a default role name, using the crud resolver. - * - * This method should not be overriden. Override `getRoleFor` instead. - * - * @param string $action - * @return string - */ - protected function buildDefaultRole($action) - { - return $this->getCrudResolver()->buildDefaultRole($this->getCrudName(), - $action); - } - - /** - * get the default form class from config - * - * @param string $action - * @return string the FQDN of the form class - */ - protected function getFormClassFor($action) - { - if ($action === 'delete') { - return $this->crudConfig[$action]['form_class'] - ?? $this->getDefaultDeleteFormClass($action); - } - - return $this->crudConfig[$action]['form_class'] - ?? $this->crudConfig['form_class']; - } - - protected function getDefaultDeleteFormClass($action) - { - return CRUDDeleteEntityForm::class; - } - - /** - * Create a form - * - * use the method `getFormClassFor` - * - * A hook is available: `customizeForm` allow you to customize the form - * if needed. - * - * It is preferable to override customizeForm instead of overriding - * this method. - * - * @param string $action - * @param mixed $entity - * @param string $formClass - * @param array $formOptions - * @return FormInterface - */ - protected function createFormFor(string $action, $entity, string $formClass = null, array $formOptions = []): FormInterface - { - $formClass = $formClass ?? $this->getFormClassFor($action); - - $form = $this->createForm($formClass, $entity, $formOptions); - - $this->customizeForm($action, $form); - - return $form; - } - - /** - * Customize the form created by createFormFor. - * - * @param string $action - * @param FormInterface $form - */ - protected function customizeForm(string $action, FormInterface $form) - { - - } - - /** - * Generate a message which explains an error about the form. - * - * Used in form actions - * - * @param string $action - * @param FormInterface $form - * @return string - */ - protected function generateFormErrorMessage(string $action, FormInterface $form): string - { - $msg = 'This form contains errors'; - - return $this->getTranslator()->trans($msg); - } - - /** - * Generate a success message when a form could be flushed successfully - * - * @param string $action - * @param mixed $entity - * @return string - */ - protected function generateFormSuccessMessage($action, $entity): string - { - switch ($action) { - case 'edit': - $msg = "crud.edit.success"; - break; - case 'new': - $msg = "crud.new.success"; - break; - case 'delete': - $msg = "crud.delete.success"; - break; - default: - $msg = "crud.default.success"; - } - - return $this->getTranslator()->trans($msg); - } - - /** - * Customize template parameters. - * - * @param string $action - * @param mixed $entity - * @param Request $request - * @param array $defaultTemplateParameters - * @return array - */ - protected function generateTemplateParameter( - string $action, - $entity, - Request $request, - array $defaultTemplateParameters = [] - ) { - return $defaultTemplateParameters; - } - - /** - * Create an entity. - * - * @param string $action - * @param Request $request - * @return object - */ - protected function createEntity(string $action, Request $request): object - { - $type = $this->getEntityClass(); - - return new $type; - } - - /** - * Get the template for the current crud. - * - * This template may be defined in configuration. If any template are - * defined, return the default template for the actions new, edit, index, - * and view. - * - * @param string $action - * @param mixed $entity the entity for the current request, or an array of entities - * @param Request $request - * @return string the path to the template - * @throws \LogicException if no template are available - */ - protected function getTemplateFor($action, $entity, Request $request) - { - if ($this->hasCustomTemplate($action, $entity, $request)) { - return $this->getActionConfig($action)['template']; - } - - switch ($action) { - case 'new': - return '@ChillMain/CRUD/new.html.twig'; - case 'edit': - return '@ChillMain/CRUD/edit.html.twig'; - case 'index': - return '@ChillMain/CRUD/index.html.twig'; - case 'view': - return '@ChillMain/CRUD/view.html.twig'; - case 'delete': - return '@ChillMain/CRUD/delete.html.twig'; - default: - throw new \LogicException("the view for action $action is not " - . "defined. You should override ".__METHOD__." to add this " - . "action"); - } - } - - /** - * @param $action - * @param $entity - * @param Request $request - * @return bool - */ - protected function hasCustomTemplate($action, $entity, Request $request): bool - { - return !empty($this->getActionConfig($action)['template']); - } - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) - { - } - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPostFlush(string $action, $entity, FormInterface $form, Request $request) - { - } - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) - { - } - - /** - * @param string $action - * @param $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onPostPersist(string $action, $entity, FormInterface $form, Request $request) - { - } - - /** - * @param $action - * @param Request $request - * @param $entity - * @return null|Response - */ - protected function onPostFetchEntity($action, Request $request, $entity): ?Response - { - return null; - } - - /** - * @param $action - * @param Request $request - * @param $entity - * @return null|Response - */ - protected function onPostCheckACL($action, Request $request, $entity): ?Response - { - return null; - } - - /** - * @param object $entity - * @param FormInterface $form - * @param Request $request - */ - protected function onFormValid(object $entity, FormInterface $form, Request $request) - { - } - - /** - * Return a redirect response depending on the value of submit button. - * - * The handled values are : - * - * * save-and-close: return to index of current crud ; - * * save-and-new: return to new page of current crud ; - * * save-and-view: return to view page of current crud ; - * - * @param string $action - * @param mixed $entity - * @param FormInterface $form - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse - */ - protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request) - { - $next = $request->request->get("submit", "save-and-close"); - - switch ($next) { - case "save-and-close": - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index'); - case "save-and-new": - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_new', $request->query->all()); - default: - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [ - 'id' => $entity->getId() - ]); - } - } - - /** - * Include services - * - * @param string $action - * @return mixed - */ - protected function getActionConfig(string $action) - { - return $this->crudConfig['actions'][$action]; - } - - /** - * @return PaginatorFactory - */ - protected function getPaginatorFactory(): PaginatorFactory - { - return $this->container->get('chill_main.paginator_factory'); - } - - /** - * @return TranslatorInterface - */ - protected function getTranslator(): TranslatorInterface - { - return $this->container->get('translator'); - } - - /** - * @return AuthorizationHelper - */ - protected function getAuthorizationHelper(): AuthorizationHelper - { - return $this->container->get(AuthorizationHelper::class); - } - - /** - * @param Role $role - * @param Scope|null $scope - * @return \Chill\MainBundle\Entity\Center[] - */ - protected function getReachableCenters(Role $role, Scope $scope = null) - { - return $this->getAuthorizationHelper() - ->getReachableCenters($this->getUser(), $role, $scope) - ; - } - - /** - * @return EventDispatcherInterface - */ - protected function getEventDispatcher(): EventDispatcherInterface - { - return $this->get(EventDispatcherInterface::class); - } - - /** - * @return Resolver - */ - protected function getCrudResolver(): Resolver - { - return $this->get(Resolver::class); - } - - /** - * @return array - */ public static function getSubscribedServices(): array { - return \array_merge( + return array_merge( parent::getSubscribedServices(), [ PaginatorFactory::class => PaginatorFactory::class, @@ -1205,4 +98,1028 @@ class CRUDController extends AbstractController ] ); } + + /** + * Base method called by index action. + * + * @return type + */ + public function index(Request $request) + { + return $this->indexEntityAction('index', $request); + } + + /** + * Base method for new action. + * + * Implemented by the method formNewAction, with action as 'new' + */ + public function new(Request $request): Response + { + return $this->formCreateAction('new', $request); + } + + public function setCrudConfig(array $config) + { + $this->crudConfig = $config; + } + + /** + * Base method for the view action. + * + * Implemented by the method viewAction, with action as 'view' + * + * @param mixed $id + */ + public function view(Request $request, $id): Response + { + return $this->viewAction('view', $request, $id); + } + + /** + * build a default role name, using the crud resolver. + * + * This method should not be overriden. Override `getRoleFor` instead. + * + * @param string $action + * + * @return string + */ + protected function buildDefaultRole($action) + { + return $this->getCrudResolver()->buildDefaultRole( + $this->getCrudName(), + $action + ); + } + + /** + * Build the base query for listing all entities, normally use in a listing + * page. + * + * This base query does not contains any `WHERE` or `SELECT` clauses. Those + * are added by other methods, like `queryEntities` and `countQueries`. + * + * @return QueryBuilder + */ + protected function buildQueryEntities(string $action, Request $request) + { + return $this->getDoctrine()->getManager() + ->createQueryBuilder() + ->select('e') + ->from($this->getEntityClass(), 'e'); + } + + /** + * check the acl. Called by every action. + * + * By default, check the role given by `getRoleFor` for the value given in + * $entity. + * + * Throw an \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException + * if not accessible. + * + * @param mixed $entity + * + * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedHttpException + */ + protected function checkACL(string $action, $entity) + { + $this->denyAccessUnlessGranted($this->getRoleFor($action), $entity); + } + + /** + * Count the number of entities. + */ + protected function countEntities(string $action, Request $request): int + { + return $this->buildQueryEntities($action, $request) + ->select('COUNT(e)') + ->getQuery() + ->getSingleScalarResult(); + } + + /** + * Create an entity. + */ + protected function createEntity(string $action, Request $request): object + { + $type = $this->getEntityClass(); + + return new $type(); + } + + /** + * Create a form. + * + * use the method `getFormClassFor` + * + * A hook is available: `customizeForm` allow you to customize the form + * if needed. + * + * It is preferable to override customizeForm instead of overriding + * this method. + * + * @param mixed $entity + * @param string $formClass + */ + protected function createFormFor(string $action, $entity, ?string $formClass = null, array $formOptions = []): FormInterface + { + $formClass = $formClass ?? $this->getFormClassFor($action); + + $form = $this->createForm($formClass, $entity, $formOptions); + + $this->customizeForm($action, $form); + + return $form; + } + + /** + * Customize the form created by createFormFor. + */ + protected function customizeForm(string $action, FormInterface $form) + { + } + + /** + * @param $id + * @param null $formClass + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse|void|null + */ + protected function deleteAction(string $action, Request $request, $id, $formClass = null) + { + $this->onPreDelete($action, $request, $id); + + $entity = $this->getEntity($action, $id, $request); + + $postFetch = $this->onPostFetchEntity($action, $request, $entity); + + if ($postFetch instanceof Response) { + return $postFetch; + } + + if (null === $entity) { + throw $this->createNotFoundException(sprintf('The %s with id %s ' + . 'is not found'), $this->getCrudName(), $id); + } + + $response = $this->checkACL($action, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + $form = $this->createFormFor($action, $entity, $formClass); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->onFormValid($entity, $form, $request); + $em = $this->getDoctrine()->getManager(); + + $this->onPreRemove($action, $entity, $form, $request); + $this->removeEntity($action, $entity, $form, $request); + $this->onPostRemove($action, $entity, $form, $request); + + $this->onPreFlush($action, $entity, $form, $request); + $em->flush(); + $this->onPostFlush($action, $entity, $form, $request); + + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); + + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); + + if ($result instanceof Response) { + return $result; + } + + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]); + } + + if ($form->isSubmitted()) { + $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); + } + + $defaultTemplateParameters = [ + 'form' => $form->createView(), + 'entity' => $entity, + 'crud_name' => $this->getCrudName(), + ]; + + return $this->render( + $this->getTemplateFor($action, $entity, $request), + $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) + ); + } + + /** + * Duplicate an entity. + * + * @return mixed + */ + protected function duplicateEntity(string $action, Request $request) + { + $id = $request->query->get('duplicate_id', 0); + $originalEntity = $this->getEntity($action, $id, $request); + + $this->getDoctrine()->getManager() + ->detach($originalEntity); + + return $originalEntity; + } + + /** + * The new (or creation) action. + * + * Some steps may be overriden during this process of rendering: + * + * This method: + * + * 1. Create or duplicate an entity: + * + * If the `duplicate` parameter is present, the entity is duplicated + * using the `duplicate` method. + * + * If not, the entity is created using the `create` method. + * 3. check ACL using `checkACL` ; + * 4. launch `onPostCheckACL`. If the result is an instance of Response, + * this response is returned ; + * 5. generate a form using `createFormFor`, and handle request on this form; + * + * If the form is valid, the entity is stored and flushed, and a redirection + * is returned. + * + * In this case, those hooks are available: + * + * * onFormValid + * * onPreFlush + * * onPostFlush + * * onBeforeRedirectAfterSubmission. If this method return an instance of + * Response, this response is returned. + * + * 5. generate default template parameters: + * + * * `entity`: the fetched entity ; + * * `crud_name`: the crud name ; + * * `form`: the formview instance. + * + * 6. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. + * + * @param type $formClass + */ + protected function formCreateAction(string $action, Request $request, $formClass = null): Response + { + if ($request->query->has('duplicate')) { + $entity = $this->duplicateEntity($action, $request); + } else { + $entity = $this->createEntity($action, $request); + } + + $response = $this->checkACL($action, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + $form = $this->createFormFor($action, $entity, $formClass); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->onFormValid($entity, $form, $request); + $em = $this->getDoctrine()->getManager(); + + $this->onPrePersist($action, $entity, $form, $request); + $em->persist($entity); + $this->onPostPersist($action, $entity, $form, $request); + + $this->onPreFlush($action, $entity, $form, $request); + $em->flush(); + $this->onPostFlush($action, $entity, $form, $request); + $this->getPaginatorFactory(); + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); + + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); + + if ($result instanceof Response) { + return $result; + } + + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', ['id' => $entity->getId()]); + } + + if ($form->isSubmitted()) { + $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); + } + + $defaultTemplateParameters = [ + 'form' => $form->createView(), + 'entity' => $entity, + 'crud_name' => $this->getCrudName(), + ]; + + return $this->render( + $this->getTemplateFor($action, $entity, $request), + $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) + ); + } + + /** + * The edit action. + * + * Some steps may be overriden during this process of rendering: + * + * This method: + * + * 1. fetch the entity, using `getEntity` + * 2. launch `onPostFetchEntity`. If postfetch is an instance of Response, + * this response is returned. + * 2. throw an HttpNotFoundException if entity is null + * 3. check ACL using `checkACL` ; + * 4. launch `onPostCheckACL`. If the result is an instance of Response, + * this response is returned ; + * 5. generate a form using `createFormFor`, and handle request on this form; + * + * If the form is valid, the entity is stored and flushed, and a redirection + * is returned. + * + * In this case, those hooks are available: + * + * * onFormValid + * * onPreFlush + * * onPostFlush + * * onBeforeRedirectAfterSubmission. If this method return an instance of + * Response, this response is returned. + * + * 5. generate default template parameters: + * + * * `entity`: the fetched entity ; + * * `crud_name`: the crud name ; + * * `form`: the formview instance. + * + * 6. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. + * + * @param mixed $id + * @param string $formClass + * + * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException + */ + protected function formEditAction(string $action, Request $request, $id, ?string $formClass = null, array $formOptions = []): Response + { + $entity = $this->getEntity($action, $id, $request); + + if (null === $entity) { + throw $this->createNotFoundException(sprintf('The %s with id %s ' + . 'is not found'), $this->getCrudName(), $id); + } + + $response = $this->checkACL($action, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + $form = $this->createFormFor($action, $entity, $formClass, $formOptions); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->onFormValid($entity, $form, $request); + $em = $this->getDoctrine()->getManager(); + + $this->onPreFlush($action, $entity, $form, $request); + $em->flush(); + $this->onPostFlush($action, $entity, $form, $request); + + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); + + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); + + if ($result instanceof Response) { + return $result; + } + + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index'); + } + + if ($form->isSubmitted()) { + $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); + } + + $defaultTemplateParameters = [ + 'form' => $form->createView(), + 'entity' => $entity, + 'crud_name' => $this->getCrudName(), + ]; + + return $this->render( + $this->getTemplateFor($action, $entity, $request), + $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) + ); + } + + /** + * Generate a message which explains an error about the form. + * + * Used in form actions + */ + protected function generateFormErrorMessage(string $action, FormInterface $form): string + { + $msg = 'This form contains errors'; + + return $this->getTranslator()->trans($msg); + } + + /** + * Generate a success message when a form could be flushed successfully. + * + * @param string $action + * @param mixed $entity + */ + protected function generateFormSuccessMessage($action, $entity): string + { + switch ($action) { + case 'edit': + $msg = 'crud.edit.success'; + + break; + + case 'new': + $msg = 'crud.new.success'; + + break; + + case 'delete': + $msg = 'crud.delete.success'; + + break; + + default: + $msg = 'crud.default.success'; + } + + return $this->getTranslator()->trans($msg); + } + + /** + * Customize template parameters. + * + * @param mixed $entity + * + * @return array + */ + protected function generateTemplateParameter( + string $action, + $entity, + Request $request, + array $defaultTemplateParameters = [] + ) { + return $defaultTemplateParameters; + } + + /** + * Include services. + * + * @return mixed + */ + protected function getActionConfig(string $action) + { + return $this->crudConfig['actions'][$action]; + } + + protected function getAuthorizationHelper(): AuthorizationHelper + { + return $this->container->get(AuthorizationHelper::class); + } + + /** + * @return string the crud name + */ + protected function getCrudName(): string + { + return $this->crudConfig['name']; + } + + protected function getCrudResolver(): Resolver + { + return $this->get(Resolver::class); + } + + protected function getDefaultDeleteFormClass($action) + { + return CRUDDeleteEntityForm::class; + } + + /** + * get the instance of the entity with the given id. + * + * @param string $id + * @param mixed $action + * + * @return object + */ + protected function getEntity($action, $id, Request $request): ?object + { + return $this->getDoctrine() + ->getRepository($this->getEntityClass()) + ->find($id); + } + + /** + * @return string the complete fqdn of the class + */ + protected function getEntityClass(): string + { + return $this->crudConfig['class']; + } + + protected function getEventDispatcher(): EventDispatcherInterface + { + return $this->get(EventDispatcherInterface::class); + } + + /** + * get the default form class from config. + * + * @param string $action + * + * @return string the FQDN of the form class + */ + protected function getFormClassFor($action) + { + if ('delete' === $action) { + return $this->crudConfig[$action]['form_class'] + ?? $this->getDefaultDeleteFormClass($action); + } + + return $this->crudConfig[$action]['form_class'] + ?? $this->crudConfig['form_class']; + } + + protected function getPaginatorFactory(): PaginatorFactory + { + return $this->container->get('chill_main.paginator_factory'); + } + + /** + * Get the result of the query. + * + * @param mixed $query + * + * @return mixed + */ + protected function getQueryResult(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) + { + return $query->getQuery()->getResult(); + } + + /** + * @return \Chill\MainBundle\Entity\Center[] + */ + protected function getReachableCenters(Role $role, ?Scope $scope = null) + { + return $this->getAuthorizationHelper() + ->getReachableCenters($this->getUser(), $role, $scope); + } + + /** + * get the role given from the config. + * + * @param string $action + * + * @return string + */ + protected function getRoleFor($action) + { + if (array_key_exists('role', $this->getActionConfig($action))) { + return $this->getActionConfig($action)['role']; + } + + return $this->buildDefaultRole($action); + } + + /** + * Get the template for the current crud. + * + * This template may be defined in configuration. If any template are + * defined, return the default template for the actions new, edit, index, + * and view. + * + * @param string $action + * @param mixed $entity the entity for the current request, or an array of entities + * + * @throws LogicException if no template are available + * + * @return string the path to the template + */ + protected function getTemplateFor($action, $entity, Request $request) + { + if ($this->hasCustomTemplate($action, $entity, $request)) { + return $this->getActionConfig($action)['template']; + } + + switch ($action) { + case 'new': + return '@ChillMain/CRUD/new.html.twig'; + + case 'edit': + return '@ChillMain/CRUD/edit.html.twig'; + + case 'index': + return '@ChillMain/CRUD/index.html.twig'; + + case 'view': + return '@ChillMain/CRUD/view.html.twig'; + + case 'delete': + return '@ChillMain/CRUD/delete.html.twig'; + + default: + throw new LogicException("the view for action {$action} is not " + . 'defined. You should override ' . __METHOD__ . ' to add this ' + . 'action'); + } + } + + protected function getTranslator(): TranslatorInterface + { + return $this->container->get('translator'); + } + + /** + * @param $action + * @param $entity + */ + protected function hasCustomTemplate($action, $entity, Request $request): bool + { + return !empty($this->getActionConfig($action)['template']); + } + + /** + * Build an index page. + * + * Some steps may be overriden during this process of rendering. + * + * This method: + * + * 1. Launch `onPreIndex` + * x. check acl. If it does return a response instance, return it + * x. launch `onPostCheckACL`. If it does return a response instance, return it + * 1. count the items, using `countEntities` + * 2. build a paginator element from the the number of entities ; + * 3. Launch `onPreIndexQuery`. If it does return a response instance, return it + * 3. build a query, using `queryEntities` + * x. fetch the results, using `getQueryResult` + * x. Launch `onPostIndexFetchQuery`. If it does return a response instance, return it + * 4. create default parameters: + * + * The default parameters are: + * + * * entities: the list en entities ; + * * crud_name: the name of the crud ; + * * paginator: a paginator element ; + * 5. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. + * + * @param string $action + * + * @return type + */ + protected function indexEntityAction($action, Request $request) + { + $this->onPreIndex($action, $request); + + $response = $this->checkACL($action, null); + + if ($response instanceof Response) { + return $response; + } + + if (!isset($entity)) { + $entity = ''; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + $totalItems = $this->countEntities($action, $request); + $paginator = $this->getPaginatorFactory()->create($totalItems); + + $response = $this->onPreIndexBuildQuery( + $action, + $request, + $totalItems, + $paginator + ); + + if ($response instanceof Response) { + return $response; + } + + $query = $this->queryEntities($action, $request, $paginator); + + $response = $this->onPostIndexBuildQuery( + $action, + $request, + $totalItems, + $paginator, + $query + ); + + if ($response instanceof Response) { + return $response; + } + + $entities = $this->getQueryResult($action, $request, $totalItems, $paginator, $query); + + $response = $this->onPostIndexFetchQuery( + $action, + $request, + $totalItems, + $paginator, + $entities + ); + + if ($response instanceof Response) { + return $response; + } + + $defaultTemplateParameters = [ + 'entities' => $entities, + 'crud_name' => $this->getCrudName(), + 'paginator' => $paginator, + ]; + + return $this->render( + $this->getTemplateFor($action, $entities, $request), + $this->generateTemplateParameter($action, $entities, $request, $defaultTemplateParameters) + ); + } + + /** + * Return a redirect response depending on the value of submit button. + * + * The handled values are : + * + * * save-and-close: return to index of current crud ; + * * save-and-new: return to new page of current crud ; + * * save-and-view: return to view page of current crud ; + * + * @param mixed $entity + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse + */ + protected function onBeforeRedirectAfterSubmission(string $action, $entity, FormInterface $form, Request $request) + { + $next = $request->request->get('submit', 'save-and-close'); + + switch ($next) { + case 'save-and-close': + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index'); + + case 'save-and-new': + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_new', $request->query->all()); + + default: + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', [ + 'id' => $entity->getId(), + ]); + } + } + + protected function onFormValid(object $entity, FormInterface $form, Request $request) + { + } + + /** + * @param $action + * @param $entity + */ + protected function onPostCheckACL($action, Request $request, $entity): ?Response + { + return null; + } + + /** + * @param $action + * @param $entity + */ + protected function onPostFetchEntity($action, Request $request, $entity): ?Response + { + return null; + } + + /** + * @param $entity + */ + protected function onPostFlush(string $action, $entity, FormInterface $form, Request $request) + { + } + + /** + * method used by indexAction. + * + * @param mixed $query + */ + protected function onPostIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $query) + { + } + + /** + * method used by indexAction. + * + * @param mixed $entities + */ + protected function onPostIndexFetchQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator, $entities) + { + } + + /** + * @param $entity + */ + protected function onPostPersist(string $action, $entity, FormInterface $form, Request $request) + { + } + + /** + * @param $entity + */ + protected function onPostRemove(string $action, $entity, FormInterface $form, Request $request) + { + } + + protected function onPreDelete(string $action, Request $request) + { + } + + /** + * @param $entity + */ + protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) + { + } + + protected function onPreIndex(string $action, Request $request) + { + } + + /** + * method used by indexAction. + */ + protected function onPreIndexBuildQuery(string $action, Request $request, int $totalItems, PaginatorInterface $paginator) + { + } + + /** + * @param $entity + */ + protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) + { + } + + /** + * @param $entity + */ + protected function onPreRemove(string $action, $entity, FormInterface $form, Request $request) + { + } + + /** + * Add ordering fields in the query build by self::queryEntities. + * + * @param mixed|QueryBuilder $query by default, an instance of QueryBuilder + * + * @return mixed|QueryBuilder + */ + protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) + { + return $query; + } + + /** + * Query the entity. + * + * By default, get all entities. + * + * The method `orderEntity` is called internally to order entities. + * + * It returns, by default, a query builder. + * + * @return type + */ + protected function queryEntities(string $action, Request $request, PaginatorInterface $paginator) + { + $query = $this->buildQueryEntities($action, $request) + ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) + ->setMaxResults($paginator->getItemsPerPage()); + + // allow to order queries and return the new query + return $this->orderQuery($action, $query, $request, $paginator); + } + + /** + * @param $entity + */ + protected function removeEntity(string $action, $entity, FormInterface $form, Request $request) + { + $this->getDoctrine() + ->getManager() + ->remove($entity); + } + + /** + * The view action. + * + * Some steps may be overriden during this process of rendering: + * + * This method: + * + * 1. fetch the entity, using `getEntity` + * 2. launch `onPostFetchEntity`. If postfetch is an instance of Response, + * this response is returned. + * 2. throw an HttpNotFoundException if entity is null + * 3. check ACL using `checkACL` ; + * 4. launch `onPostCheckACL`. If the result is an instance of Response, + * this response is returned ; + * 5. generate default template parameters: + * + * * `entity`: the fetched entity ; + * * `crud_name`: the crud name + * 6. Launch rendering, the parameter is fetch using `getTemplateFor` + * The parameters may be personnalized using `generateTemplateParameter`. + * + * @param mixed $id + * @param mixed $_format + */ + protected function viewAction(string $action, Request $request, $id, $_format = 'html'): Response + { + $entity = $this->getEntity($action, $id, $request); + + $postFetch = $this->onPostFetchEntity($action, $request, $entity); + + if ($postFetch instanceof Response) { + return $postFetch; + } + + if (null === $entity) { + throw $this->createNotFoundException(sprintf('The %s with id %s ' + . 'is not found', $this->getCrudName(), $id)); + } + + $response = $this->checkACL($action, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + if ('html' === $_format) { + $defaultTemplateParameters = [ + 'entity' => $entity, + 'crud_name' => $this->getCrudName(), + ]; + + return $this->render( + $this->getTemplateFor($action, $entity, $request), + $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) + ); + } + + if ('json' === $_format) { + $context = $this->getContextForSerialization($action, $request, $entity, $_format); + + return $this->json($entity, Response::HTTP_OK, [], $context); + } + + throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented'); + } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Form/CRUDDeleteEntityForm.php b/src/Bundle/ChillMainBundle/CRUD/Form/CRUDDeleteEntityForm.php index 6b382fca3..277bcca51 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Form/CRUDDeleteEntityForm.php +++ b/src/Bundle/ChillMainBundle/CRUD/Form/CRUDDeleteEntityForm.php @@ -1,33 +1,18 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\CRUD\Form; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; - /** - * Class CRUDDeleteEntityForm - * - * @package Chill\MainBundle\CRUD\Form + * Class CRUDDeleteEntityForm. */ class CRUDDeleteEntityForm extends AbstractType { diff --git a/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php b/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php index f6242a0f1..aace345cc 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php +++ b/src/Bundle/ChillMainBundle/CRUD/Resolver/Resolver.php @@ -1,122 +1,115 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\CRUD\Resolver; use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\PropertyAccess\PropertyAccess; +use LogicException; + +use function array_key_exists; +use function strtoupper; /** - * Class Resolver - * - * @package Chill\MainBundle\CRUD\Resolver + * Class Resolver. */ class Resolver { /** - * @var EntityManagerInterface + * The key to get the role necessary for the action. */ - protected $em; - + public const ROLE = 'role'; + /** - * @var \Symfony\Component\PropertyAccess\PropertyAccessor + * @deprecated */ - protected $propertyAccess; - + public const ROLE_EDIT = 'role.edit'; + + /** + * @deprecated + */ + public const ROLE_VIEW = 'role.view'; + /** * @var array */ protected $crudConfig; - + /** - * @deprecated + * @var EntityManagerInterface */ - const ROLE_VIEW = 'role.view'; - + protected $em; + /** - * @deprecated + * @var \Symfony\Component\PropertyAccess\PropertyAccessor */ - const ROLE_EDIT = 'role.edit'; - - /** - * The key to get the role necessary for the action - */ - const ROLE = 'role'; - + protected $propertyAccess; + /** * Resolver constructor. - * - * @param EntityManagerInterface $em - * @param array $crudConfig */ - function __construct(EntityManagerInterface $em, array $crudConfig) + public function __construct(EntityManagerInterface $em, array $crudConfig) { $this->em = $em; - - foreach($crudConfig as $conf) { + + foreach ($crudConfig as $conf) { $this->crudConfig[$conf['name']] = $conf; } } - - /** - * @param $key - * @param $crudName - * @param null $action - * @return string - */ - public function getConfigValue($key, $crudName, $action = null) - { - $config = $this->crudConfig[$crudName]; - - switch ($key) { - case self::ROLE: - return $config['actions'][$action]['role'] ?? $this->buildDefaultRole($crudName, $action); - } - } - + /** * @param $crudName * @param $action + * * @return string */ public function buildDefaultRole($crudName, $action) { if (empty($this->crudConfig[$crudName]['base_role'])) { - throw new \LogicException(sprintf("the base role is not defined. You must define " - . "on or override %s or %s methods", __METHOD__, "getRoleFor")); + throw new LogicException(sprintf('the base role is not defined. You must define ' + . 'on or override %s or %s methods', __METHOD__, 'getRoleFor')); } - - return \strtoupper( - $this->crudConfig[$crudName]['base_role']. - '_'. - $action); + + return strtoupper( + $this->crudConfig[$crudName]['base_role'] . + '_' . + $action + ); } - + + /** + * @param $key + * @param $crudName + * @param null $action + * + * @return string + */ + public function getConfigValue($key, $crudName, $action = null) + { + $config = $this->crudConfig[$crudName]; + + switch ($key) { + case self::ROLE: + return $config['actions'][$action]['role'] ?? $this->buildDefaultRole($crudName, $action); + } + } + /** * @param $crudName * @param $action + * * @return bool */ public function hasAction($crudName, $action) { - return \array_key_exists($action, - $this->crudConfig[$crudName]['actions']); + return array_key_exists( + $action, + $this->crudConfig[$crudName]['actions'] + ); } } diff --git a/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php b/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php index 32068e518..4fd9f3975 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php +++ b/src/Bundle/ChillMainBundle/CRUD/Routing/CRUDRoutesLoader.php @@ -1,58 +1,48 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\CRUD\Routing; +use RuntimeException; use Symfony\Component\Config\Loader\Loader; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\HttpFoundation\Request; -use Chill\MainBundle\CRUD\Controller\ApiController; -use Chill\MainBundle\CRUD\Controller\CRUDController; + +use function array_filter; +use function array_keys; +use function in_array; /** * Class CRUDRoutesLoader - * Load the route for CRUD - * - * @package Chill\MainBundle\CRUD\Routing + * Load the route for CRUD. */ class CRUDRoutesLoader extends Loader { - protected array $crudConfig = []; - - protected array $apiCrudConfig = []; - - /** - * @var bool - */ - private $isLoaded = false; + private const ALL_INDEX_METHODS = [Request::METHOD_GET, Request::METHOD_HEAD]; private const ALL_SINGLE_METHODS = [ Request::METHOD_GET, Request::METHOD_POST, Request::METHOD_PUT, - Request::METHOD_DELETE + Request::METHOD_DELETE, ]; - private const ALL_INDEX_METHODS = [ Request::METHOD_GET, Request::METHOD_HEAD ]; - + protected array $apiCrudConfig = []; + + protected array $crudConfig = []; + + /** + * @var bool + */ + private $isLoaded = false; + /** * CRUDRoutesLoader constructor. * @@ -64,89 +54,57 @@ class CRUDRoutesLoader extends Loader $this->crudConfig = $crudConfig; $this->apiConfig = $apiConfig; } - + /** + * Load routes for CRUD and CRUD Api. + * * @param mixed $resource - * @param null $type - * @return bool - */ - public function supports($resource, $type = null) - { - return 'CRUD' === $type; - } - - /** - * Load routes for CRUD and CRUD Api + * @param mixed|null $type */ public function load($resource, $type = null): RouteCollection { if (true === $this->isLoaded) { - throw new \RuntimeException('Do not add the "CRUD" loader twice'); + throw new RuntimeException('Do not add the "CRUD" loader twice'); } $collection = new RouteCollection(); - + foreach ($this->crudConfig as $crudConfig) { $collection->addCollection($this->loadCrudConfig($crudConfig)); } + foreach ($this->apiConfig as $crudConfig) { $collection->addCollection($this->loadApi($crudConfig)); } return $collection; } - - /** - * Load routes for CRUD (without api) - * - * @param $crudConfig - * @return RouteCollection - */ - protected function loadCrudConfig($crudConfig): RouteCollection - { - $collection = new RouteCollection(); - $controller ='cscrud_'.$crudConfig['name'].'_controller'; - foreach ($crudConfig['actions'] as $name => $action) { - // defaults (controller name) - $defaults = [ - '_controller' => $controller.':'.($action['controller_action'] ?? $name) - ]; - - if ($name === 'index') { - $path = "{_locale}".$crudConfig['base_path']; - $route = new Route($path, $defaults); - } elseif ($name === 'new') { - $path = "{_locale}".$crudConfig['base_path'].'/'.$name; - $route = new Route($path, $defaults); - } else { - $path = "{_locale}".$crudConfig['base_path'].($action['path'] ?? '/{id}/'.$name); - $requirements = $action['requirements'] ?? [ - '{id}' => '\d+' - ]; - $route = new Route($path, $defaults, $requirements); - } - - $collection->add('chill_crud_'.$crudConfig['name'].'_'.$name, $route); - } - - return $collection; + /** + * @param mixed $resource + * @param null $type + * + * @return bool + */ + public function supports($resource, $type = null) + { + return 'CRUD' === $type; } /** - * Load routes for api single + * Load routes for api single. * * @param $crudConfig - * @return RouteCollection */ protected function loadApi(array $crudConfig): RouteCollection { $collection = new RouteCollection(); - $controller ='csapi_'.$crudConfig['name'].'_controller'; + $controller = 'csapi_' . $crudConfig['name'] . '_controller'; foreach ($crudConfig['actions'] as $name => $action) { // filter only on single actions - $singleCollection = $action['single-collection'] ?? $name === '_entity' ? 'single' : NULL; + $singleCollection = $action['single-collection'] ?? '_entity' === $name ? 'single' : null; + if ('collection' === $singleCollection) { // continue; } @@ -155,80 +113,132 @@ class CRUDRoutesLoader extends Loader switch ($name) { case '_entity': $controllerAction = 'entityApi'; + break; + case '_index': $controllerAction = 'indexApi'; + break; + default: - $controllerAction = $name.'Api'; + $controllerAction = $name . 'Api'; + break; } $defaults = [ - '_controller' => $controller.':'.($action['controller_action'] ?? $controllerAction) + '_controller' => $controller . ':' . ($action['controller_action'] ?? $controllerAction), ]; // path are rewritten // if name === 'default', we rewrite it to nothing :-) - $localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name; + $localName = in_array($name, ['_entity', '_index']) ? '' : '/' . $name; + if ('collection' === $action['single-collection'] || '_index' === $name) { - $localPath = $action['path'] ?? $localName.'.{_format}'; + $localPath = $action['path'] ?? $localName . '.{_format}'; } else { - $localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}'; + $localPath = $action['path'] ?? '/{id}' . $localName . '.{_format}'; } - $path = $crudConfig['base_path'].$localPath; + $path = $crudConfig['base_path'] . $localPath; - $requirements = $action['requirements'] ?? [ '{id}' => '\d+' ]; + $requirements = $action['requirements'] ?? ['{id}' => '\d+']; - $methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; }, - ARRAY_FILTER_USE_BOTH)); + $methods = array_keys(array_filter( + $action['methods'], + function ($value, $key) { + return $value; + }, + ARRAY_FILTER_USE_BOTH + )); $route = new Route($path, $defaults, $requirements); $route->setMethods($methods); - - $collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route); + + $collection->add('chill_api_single_' . $crudConfig['name'] . '_' . $name, $route); } return $collection; } /** - * Load routes for api multi + * Load routes for api multi. * * @param $crudConfig - * @return RouteCollection */ protected function loadApiMultiConfig(array $crudConfig): RouteCollection { $collection = new RouteCollection(); - $controller ='csapi_'.$crudConfig['name'].'_controller'; + $controller = 'csapi_' . $crudConfig['name'] . '_controller'; foreach ($crudConfig['actions'] as $name => $action) { // filter only on single actions - $singleCollection = $action['single-collection'] ?? $name === '_index' ? 'collection' : NULL; + $singleCollection = $action['single-collection'] ?? '_index' === $name ? 'collection' : null; + if ('single' === $singleCollection) { continue; } $defaults = [ - '_controller' => $controller.':'.($action['controller_action'] ?? '_entity' === $name ? 'entityApi' : $name.'Api') + '_controller' => $controller . ':' . ($action['controller_action'] ?? '_entity' === $name ? 'entityApi' : $name . 'Api'), ]; // path are rewritten // if name === 'default', we rewrite it to nothing :-) - $localName = '_entity' === $name ? '' : '/'.$name; - $localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}'; - $path = $crudConfig['base_path'].$localPath; + $localName = '_entity' === $name ? '' : '/' . $name; + $localPath = $action['path'] ?? '/{id}' . $localName . '.{_format}'; + $path = $crudConfig['base_path'] . $localPath; - $requirements = $action['requirements'] ?? [ '{id}' => '\d+' ]; + $requirements = $action['requirements'] ?? ['{id}' => '\d+']; - $methods = \array_keys(\array_filter($action['methods'], function($value, $key) { return $value; }, - ARRAY_FILTER_USE_BOTH)); + $methods = array_keys(array_filter( + $action['methods'], + function ($value, $key) { + return $value; + }, + ARRAY_FILTER_USE_BOTH + )); $route = new Route($path, $defaults, $requirements); $route->setMethods($methods); - - $collection->add('chill_api_single_'.$crudConfig['name'].'_'.$name, $route); + + $collection->add('chill_api_single_' . $crudConfig['name'] . '_' . $name, $route); + } + + return $collection; + } + + /** + * Load routes for CRUD (without api). + * + * @param $crudConfig + */ + protected function loadCrudConfig($crudConfig): RouteCollection + { + $collection = new RouteCollection(); + $controller = 'cscrud_' . $crudConfig['name'] . '_controller'; + + foreach ($crudConfig['actions'] as $name => $action) { + // defaults (controller name) + $defaults = [ + '_controller' => $controller . ':' . ($action['controller_action'] ?? $name), + ]; + + if ('index' === $name) { + $path = '{_locale}' . $crudConfig['base_path']; + $route = new Route($path, $defaults); + } elseif ('new' === $name) { + $path = '{_locale}' . $crudConfig['base_path'] . '/' . $name; + $route = new Route($path, $defaults); + } else { + $path = '{_locale}' . $crudConfig['base_path'] . ($action['path'] ?? '/{id}/' . $name); + $requirements = $action['requirements'] ?? [ + '{id}' => '\d+', + ]; + $route = new Route($path, $defaults, $requirements); + } + + $collection->add('chill_crud_' . $crudConfig['name'] . '_' . $name, $route); } return $collection; diff --git a/src/Bundle/ChillMainBundle/CRUD/Templating/TwigCRUDResolver.php b/src/Bundle/ChillMainBundle/CRUD/Templating/TwigCRUDResolver.php index 00956bf2e..40b792bb6 100644 --- a/src/Bundle/ChillMainBundle/CRUD/Templating/TwigCRUDResolver.php +++ b/src/Bundle/ChillMainBundle/CRUD/Templating/TwigCRUDResolver.php @@ -1,36 +1,21 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\CRUD\Templating; use Chill\MainBundle\CRUD\Resolver\Resolver; -use Twig\TwigFilter; -use Twig\TwigFunction; use Twig\Extension\AbstractExtension; -use Twig\Environment; +use Twig\TwigFunction; /** * Class TwigCRUDResolver - * Twig filters to display data in crud template - * - * @package Chill\MainBundle\CRUD\Templating + * Twig filters to display data in crud template. */ class TwigCRUDResolver extends AbstractExtension { @@ -38,49 +23,54 @@ class TwigCRUDResolver extends AbstractExtension * @var Resolver */ protected $resolver; - + /** * TwigCRUDResolver constructor. - * - * @param Resolver $resolver */ - function __construct(Resolver $resolver) + public function __construct(Resolver $resolver) { $this->resolver = $resolver; } - - /** - * @return array|TwigFunction[] - */ - public function getFunctions() - { - return [ - new TwigFunction('chill_crud_config', [$this, 'getConfig'], - ['is_safe' => 'html']), - new TwigFunction('chill_crud_action_exists', [$this, 'hasAction'], - []), - ]; - } - + /** * @param $configKey * @param $crudName * @param null $action + * * @return string */ public function getConfig($configKey, $crudName, $action = null) { return $this->resolver->getConfigValue($configKey, $crudName, $action); } - + + /** + * @return array|TwigFunction[] + */ + public function getFunctions() + { + return [ + new TwigFunction( + 'chill_crud_config', + [$this, 'getConfig'], + ['is_safe' => 'html'] + ), + new TwigFunction( + 'chill_crud_action_exists', + [$this, 'hasAction'], + [] + ), + ]; + } + /** * @param $crudName * @param $action + * * @return bool */ public function hasAction($crudName, $action) { return $this->resolver->hasAction($crudName, $action); } - } diff --git a/src/Bundle/ChillMainBundle/Center/GroupingCenterInterface.php b/src/Bundle/ChillMainBundle/Center/GroupingCenterInterface.php index 5f10d35c8..442ebffa2 100644 --- a/src/Bundle/ChillMainBundle/Center/GroupingCenterInterface.php +++ b/src/Bundle/ChillMainBundle/Center/GroupingCenterInterface.php @@ -1,27 +1,33 @@ passwordEncoder = $passwordEncoder; $this->validator = $validator; $this->logger = $logger; - - + $this->userRepository = $em->getRepository(User::class); - + parent::__construct('chill:main:import-users'); } - - + protected function appendUserToFile(User $user) + { + $this->output->insertOne([ + $user->getEmail(), + $user->getUsername(), + $user->getId(), + ]); + } + + protected function concatenateViolations(ConstraintViolationListInterface $list) + { + $str = []; + + foreach ($list as $e) { + /* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */ + $str[] = $e->getMessage(); + } + + return implode(';', $str); + } + protected function configure() { $this @@ -126,82 +149,92 @@ class ChillImportUsersCommand extends Command ->addArgument('csvfile', InputArgument::REQUIRED, 'Path to the csv file. Columns are: `username`, `email`, `center` (can contain alias), `permission group`') ->addOption('grouping-centers', null, InputOption::VALUE_OPTIONAL, 'Path to a csv file to aggregate multiple centers into a single alias') ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do not commit the changes') - ->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file') - ; + ->addOption('csv-dump', null, InputOption::VALUE_REQUIRED, 'A path to dump a summary of the created file'); } - protected function execute(InputInterface $input, OutputInterface $output) + /** + * @param \Chill\MainBundle\Command\PermissionGroup $pg + */ + protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter { - $this->tempOutput = $output; - $this->tempInput = $input; - - if ($input->getOption('dry-run')) { - $this->doChanges = false; - } - - $this->prepareWriter(); - - if ($input->hasOption('grouping-centers')) { - $this->prepareGroupingCenters(); - } - - try { - $this->loadUsers(); - } - catch(\Exception $e) { - throw $e; - } - } - - protected function prepareWriter() - { - $this->output = $output = Writer::createFromPath($this->tempInput - ->getOption('csv-dump'), 'a+'); - - $output->insertOne([ - 'email', - 'username', - 'id' - ]); - } - - protected function appendUserToFile(User $user) - { - $this->output->insertOne( [ - $user->getEmail(), - $user->getUsername(), - $user->getId() - ]); - } - - protected function loadUsers() - { - $reader = Reader::createFromPath($this->tempInput->getArgument('csvfile')); - $reader->setHeaderOffset(0); - - foreach ($reader->getRecords() as $line => $r) { - $this->logger->debug("starting handling new line", [ - 'line' => $line - ]); - - if ($this->doesUserExists($r)) { - $this->tempOutput->writeln(sprintf("User with username '%s' already " - . "exists, skipping", $r["username"])); - - $this->logger->info("One user already exists, skipping creation", [ - 'username_in_file' => $r['username'], - 'email_in_file' => $r['email'], - 'line' => $line - ]); - - continue; + if (array_key_exists($center->getId(), $this->groupCenters)) { + if (array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) { + return $this->groupCenters[$center->getId()][$pg->getId()]; } - - $user = $this->createUser($line, $r); - $this->appendUserToFile($user); } + + $repository = $this->em->getRepository(GroupCenter::class); + + $groupCenter = $repository->findOneBy([ + 'center' => $center, + 'permissionsGroup' => $pg, + ]); + + if (null === $groupCenter) { + $groupCenter = new GroupCenter(); + $groupCenter + ->setCenter($center) + ->setPermissionsGroup($pg); + + $this->em->persist($groupCenter); + } + + $this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter; + + return $groupCenter; } - + + protected function createUser($offset, $data) + { + $user = new User(); + $user + ->setEmail(trim($data['email'])) + ->setUsername(trim($data['username'])) + ->setEnabled(true) + ->setPassword($this->passwordEncoder->encodePassword( + $user, + bin2hex(random_bytes(32)) + )); + + $errors = $this->validator->validate($user); + + if ($errors->count() > 0) { + $errorMessages = $this->concatenateViolations($errors); + + $this->tempOutput->writeln(sprintf('%d errors found with user with username "%s" at line %d', $errors->count(), $data['username'], $offset)); + $this->tempOutput->writeln($errorMessages); + + throw new RuntimeException('Found errors while creating an user. ' + . 'Watch messages in command output'); + } + + $pgs = $this->getPermissionGroup($data['permission group']); + $centers = $this->getCenters($data['center']); + + foreach ($pgs as $pg) { + foreach ($centers as $center) { + $groupcenter = $this->createOrGetGroupCenter($center, $pg); + + if (false === $user->getGroupCenters()->contains($groupcenter)) { + $user->addGroupCenter($groupcenter); + } + } + } + + if ($this->doChanges) { + $this->em->persist($user); + $this->em->flush(); + } + + $this->logger->notice('Create user', [ + 'username' => $user->getUsername(), + 'id' => $user->getId(), + 'nb_of_groupCenters' => $user->getGroupCenters()->count(), + ]); + + return $user; + } + protected function doesUserExists($data) { if ($this->userRepository->countByUsernameOrEmail($data['username']) > 0) { @@ -211,238 +244,210 @@ class ChillImportUsersCommand extends Command if ($this->userRepository->countByUsernameOrEmail($data['email']) > 0) { return true; } - + return false; } - - protected function createUser($offset, $data) - { - $user = new User(); - $user - ->setEmail(\trim($data['email'])) - ->setUsername(\trim($data['username'])) - ->setEnabled(true) - ->setPassword($this->passwordEncoder->encodePassword($user, - \bin2hex(\random_bytes(32)))) - ; - - $errors = $this->validator->validate($user); - - if ($errors->count() > 0) { - $errorMessages = $this->concatenateViolations($errors); - - $this->tempOutput->writeln(sprintf("%d errors found with user with username \"%s\" at line %d", $errors->count(), $data['username'], $offset)); - $this->tempOutput->writeln($errorMessages); - throw new \RuntimeException("Found errors while creating an user. " - . "Watch messages in command output"); - } - - $pgs = $this->getPermissionGroup($data['permission group']); - $centers = $this->getCenters($data['center']); - - foreach($pgs as $pg) { - foreach ($centers as $center) { - $groupcenter = $this->createOrGetGroupCenter($center, $pg); - - if (FALSE === $user->getGroupCenters()->contains($groupcenter)) { - $user->addGroupCenter($groupcenter); - } - } - } - + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->tempOutput = $output; + $this->tempInput = $input; - if ($this->doChanges) { - $this->em->persist($user); - $this->em->flush(); + if ($input->getOption('dry-run')) { + $this->doChanges = false; } - - $this->logger->notice("Create user", [ - 'username' => $user->getUsername(), - 'id' => $user->getId(), - 'nb_of_groupCenters' => $user->getGroupCenters()->count() - ]); - return $user; - } - - protected function getPermissionGroup($alias) - { - if (\array_key_exists($alias, $this->permissionGroups)) { - return $this->permissionGroups[$alias]; + $this->prepareWriter(); + + if ($input->hasOption('grouping-centers')) { + $this->prepareGroupingCenters(); } - - $permissionGroupsByName = []; - - foreach($this->em->getRepository(PermissionsGroup::class) - ->findAll() as $permissionGroup) { - $permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup; - } - - if (count($permissionGroupsByName) === 0) { - throw new \RuntimeException("no permission groups found. Create them " - . "before importing users"); - } - - $question = new ChoiceQuestion("To which permission groups associate with \"$alias\" ?", - \array_keys($permissionGroupsByName)); - $question - ->setMultiselect(true) - ->setAutocompleterValues(\array_keys($permissionGroupsByName)) - ->setNormalizer(function($value) { - if (NULL === $value) { return ''; } - - return \trim($value); - }) - ; - $helper = $this->getHelper('question'); - - $keys = $helper->ask($this->tempInput, $this->tempOutput, $question); - - $this->tempOutput->writeln("You have chosen ".\implode(", ", $keys)); - - if ($helper->ask($this->tempInput, $this->tempOutput, - new ConfirmationQuestion("Are you sure ?", true))) { - - foreach ($keys as $key) { - $this->permissionGroups[$alias][] = $permissionGroupsByName[$key]; - } - - return $this->permissionGroups[$alias]; - } else { - $this->logger->error("Error while responding to a a question"); - - $this->tempOutput("Ok, I accept, but I do not know what to do. Please try again."); - - throw new \RuntimeException("Error while responding to a question"); + + try { + $this->loadUsers(); + } catch (Exception $e) { + throw $e; } } - - /** - * - * @param Center $center - * @param \Chill\MainBundle\Command\PermissionGroup $pg - * @return GroupCenter - */ - protected function createOrGetGroupCenter(Center $center, PermissionsGroup $pg): GroupCenter - { - if (\array_key_exists($center->getId(), $this->groupCenters)) { - if (\array_key_exists($pg->getId(), $this->groupCenters[$center->getId()])) { - return $this->groupCenters[$center->getId()][$pg->getId()]; - } - } - - $repository = $this->em->getRepository(GroupCenter::class); - - $groupCenter = $repository->findOneBy(array( - 'center' => $center, - 'permissionsGroup' => $pg - )); - - if ($groupCenter === NULL) { - $groupCenter = new GroupCenter(); - $groupCenter - ->setCenter($center) - ->setPermissionsGroup($pg) - ; - - $this->em->persist($groupCenter); - } - - $this->groupCenters[$center->getId()][$pg->getId()] = $groupCenter; - - return $groupCenter; - } - - protected function prepareGroupingCenters() - { - $reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers')); - $reader->setHeaderOffset(0); - - foreach ($reader->getRecords() as $r) { - $this->centers[$r['alias']] = - \array_merge( - $this->centers[$r['alias']] ?? [], - $this->getCenters($r['center'] - ) - ); - } - } - + /** * return a list of centers matching the name of alias. - * + * * If the name match one center, this center is returned in an array. - * - * If the name match an alias, the centers corresponding to the alias are + * + * If the name match an alias, the centers corresponding to the alias are * returned in an array. - * + * * If the center is not found or alias is not created, a new center is created * and suggested to user - * + * * @param string $name the name of the center or the alias regrouping center + * * @return Center[] */ protected function getCenters($name) { // sanitize - $name = \trim($name); - - if (\array_key_exists($name, $this->centers)) { + $name = trim($name); + + if (array_key_exists($name, $this->centers)) { return $this->centers[$name]; } - + // search for a center with given name $center = $this->em->getRepository(Center::class) ->findOneByName($name); - + if ($center instanceof Center) { $this->centers[$name] = [$center]; - + return $this->centers[$name]; } - + // suggest and create $center = (new Center()) ->setName($name); - - $this->tempOutput->writeln("Center with name \"$name\" not found."); + + $this->tempOutput->writeln("Center with name \"{$name}\" not found."); $qFormatter = $this->getHelper('question'); - $question = new ConfirmationQuestion("Create a center with name \"$name\" ?", true); - + $question = new ConfirmationQuestion("Create a center with name \"{$name}\" ?", true); + if ($qFormatter->ask($this->tempInput, $this->tempOutput, $question)) { - $this->centers[$name] = [ $center ]; - + $this->centers[$name] = [$center]; + $errors = $this->validator->validate($center); - + if ($errors->count() > 0) { $errorMessages = $this->concatenateViolations($errors); - - $this->tempOutput->writeln(sprintf("%d errors found with center with name \"%s\"", $errors->count(), $name)); + + $this->tempOutput->writeln(sprintf('%d errors found with center with name "%s"', $errors->count(), $name)); $this->tempOutput->writeln($errorMessages); - - throw new \RuntimeException("Found errors while creating one center. " - . "Watch messages in command output"); + + throw new RuntimeException('Found errors while creating one center. ' + . 'Watch messages in command output'); } - + $this->em->persist($center); - + return $this->centers[$name]; } - + return null; } - - protected function concatenateViolations(ConstraintViolationListInterface $list) + + protected function getPermissionGroup($alias) { - $str = []; - - foreach ($list as $e) { - /* @var $e \Symfony\Component\Validator\ConstraintViolationInterface */ - $str[] = $e->getMessage(); + if (array_key_exists($alias, $this->permissionGroups)) { + return $this->permissionGroups[$alias]; } - - return \implode(";", $str); + + $permissionGroupsByName = []; + + foreach ( + $this->em->getRepository(PermissionsGroup::class) + ->findAll() as $permissionGroup + ) { + $permissionGroupsByName[$permissionGroup->getName()] = $permissionGroup; + } + + if (count($permissionGroupsByName) === 0) { + throw new RuntimeException('no permission groups found. Create them ' + . 'before importing users'); + } + + $question = new ChoiceQuestion( + "To which permission groups associate with \"{$alias}\" ?", + array_keys($permissionGroupsByName) + ); + $question + ->setMultiselect(true) + ->setAutocompleterValues(array_keys($permissionGroupsByName)) + ->setNormalizer(function ($value) { + if (null === $value) { + return ''; + } + + return trim($value); + }); + $helper = $this->getHelper('question'); + + $keys = $helper->ask($this->tempInput, $this->tempOutput, $question); + + $this->tempOutput->writeln('You have chosen ' . implode(', ', $keys)); + + if ( + $helper->ask( + $this->tempInput, + $this->tempOutput, + new ConfirmationQuestion('Are you sure ?', true) + ) + ) { + foreach ($keys as $key) { + $this->permissionGroups[$alias][] = $permissionGroupsByName[$key]; + } + + return $this->permissionGroups[$alias]; + } + $this->logger->error('Error while responding to a a question'); + + $this->tempOutput('Ok, I accept, but I do not know what to do. Please try again.'); + + throw new RuntimeException('Error while responding to a question'); + } + + protected function loadUsers() + { + $reader = Reader::createFromPath($this->tempInput->getArgument('csvfile')); + $reader->setHeaderOffset(0); + + foreach ($reader->getRecords() as $line => $r) { + $this->logger->debug('starting handling new line', [ + 'line' => $line, + ]); + + if ($this->doesUserExists($r)) { + $this->tempOutput->writeln(sprintf("User with username '%s' already " + . 'exists, skipping', $r['username'])); + + $this->logger->info('One user already exists, skipping creation', [ + 'username_in_file' => $r['username'], + 'email_in_file' => $r['email'], + 'line' => $line, + ]); + + continue; + } + + $user = $this->createUser($line, $r); + $this->appendUserToFile($user); + } + } + + protected function prepareGroupingCenters() + { + $reader = Reader::createFromPath($this->tempInput->getOption('grouping-centers')); + $reader->setHeaderOffset(0); + + foreach ($reader->getRecords() as $r) { + $this->centers[$r['alias']] = + array_merge( + $this->centers[$r['alias']] ?? [], + $this->getCenters( + $r['center'] + ) + ); + } + } + + protected function prepareWriter() + { + $this->output = $output = Writer::createFromPath($this->tempInput + ->getOption('csv-dump'), 'a+'); + + $output->insertOne([ + 'email', + 'username', + 'id', + ]); } - } diff --git a/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php b/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php index bea2fa1a5..ea400e676 100644 --- a/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php +++ b/src/Bundle/ChillMainBundle/Command/ChillUserSendRenewPasswordCodeCommand.php @@ -1,88 +1,93 @@ logger = $logger; $this->em = $em; $this->recoverPasswordHelper = $recoverPasswordHelper; $this->eventDispatcher = $eventDispatcher; - + parent::__construct(); } - - protected function configure() { $this @@ -91,113 +96,116 @@ class ChillUserSendRenewPasswordCodeCommand extends Command ->addArgument('csvfile', InputArgument::REQUIRED, 'CSV file with the list of users') ->addOption('template', null, InputOption::VALUE_REQUIRED, 'Template for email') ->addOption('expiration', null, InputOption::VALUE_REQUIRED, 'Expiration of the link, as an unix timestamp') - ->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password') - ; + ->addOption('subject', null, InputOption::VALUE_REQUIRED, 'Subject of the email', 'Recover your password'); } protected function execute(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->output = $output; - + $reader = $this->getReader(); - - foreach($reader->getRecords() as $offset => $r) { + + foreach ($reader->getRecords() as $offset => $r) { $user = $this->getUser($r); - - if ($user === null) { + + if (null === $user) { $this->onUserNotFound($r, $offset); + continue; } - + $this->sendRecoverCode($user); } } - - protected function sendRecoverCode(User $user) - { - if (empty($user->getEmail())) { - $this->logger->alert("User without email", [ - 'user_id' => $user->getId(), - 'username' => $user->getUsername() - ]); - - return; - } - - $template = $this->input->getOption('template'); - $expiration = \DateTime::createFromFormat('U', - $this->input->getOption('expiration')); - - $this->recoverPasswordHelper - ->sendRecoverEmail( - $user, - $expiration, - $template, - [ 'expiration' => $expiration], - false, - [ '_locale' => 'fr' ], - $this->input->getOption('subject') - ); - } - - protected function onUserNotFound($row, $offset) - { - $this->logger->alert('User not found', \array_merge([ - 'offset' => $offset - ], $row)); - } - - protected function getUser($row) - { - /* @var $userRepository \Chill\MainBundle\Repository\UserRepository */ - $userRepository = $this->em->getRepository(User::class); - - try { - if (\array_key_exists('email', $row)) { - return $userRepository->findOneByUsernameOrEmail(\trim($row['email'])); - } - } catch (\Doctrine\ORM\NoResultException $e) { - // continue, we will try username - } - - try { - if (\array_key_exists('username', $row)) { - return $userRepository->findOneByUsernameOrEmail(\trim($row['username'])); - } - } catch (\Doctrine\ORM\NoResultException $e) { - return null; - } - } - + /** - * + * @throws Exception + * * @return Reader - * @throws \Exception */ protected function getReader() { try { $reader = Reader::createFromPath($this->input->getArgument('csvfile')); - } catch (\Exception $e) { - $this->logger->error("The csv file could not be read", [ - 'path' => $this->input->getArgument('csvfile') + } catch (Exception $e) { + $this->logger->error('The csv file could not be read', [ + 'path' => $this->input->getArgument('csvfile'), ]); - + throw $e; } - + $reader->setHeaderOffset(0); - + $headers = $reader->getHeader(); - - if (FALSE === \in_array('username', $headers) - && FALSE === \in_array('email', $headers)) { - throw new \InvalidArgumentException("The csv file does not have an " - . "username or email header"); + + if ( + false === in_array('username', $headers) + && false === in_array('email', $headers) + ) { + throw new InvalidArgumentException('The csv file does not have an ' + . 'username or email header'); } - + return $reader; } + protected function getUser($row) + { + /* @var $userRepository \Chill\MainBundle\Repository\UserRepository */ + $userRepository = $this->em->getRepository(User::class); + + try { + if (array_key_exists('email', $row)) { + return $userRepository->findOneByUsernameOrEmail(trim($row['email'])); + } + } catch (\Doctrine\ORM\NoResultException $e) { + // continue, we will try username + } + + try { + if (array_key_exists('username', $row)) { + return $userRepository->findOneByUsernameOrEmail(trim($row['username'])); + } + } catch (\Doctrine\ORM\NoResultException $e) { + return null; + } + } + + protected function onUserNotFound($row, $offset) + { + $this->logger->alert('User not found', array_merge([ + 'offset' => $offset, + ], $row)); + } + + protected function sendRecoverCode(User $user) + { + if (empty($user->getEmail())) { + $this->logger->alert('User without email', [ + 'user_id' => $user->getId(), + 'username' => $user->getUsername(), + ]); + + return; + } + + $template = $this->input->getOption('template'); + $expiration = DateTime::createFromFormat( + 'U', + $this->input->getOption('expiration') + ); + + $this->recoverPasswordHelper + ->sendRecoverEmail( + $user, + $expiration, + $template, + ['expiration' => $expiration], + false, + ['_locale' => 'fr'], + $this->input->getOption('subject') + ); + } } diff --git a/src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php b/src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php index a5c53a551..4f816cf6d 100644 --- a/src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php +++ b/src/Bundle/ChillMainBundle/Command/LoadAndUpdateLanguagesCommand.php @@ -1,69 +1,57 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Command; use Doctrine\ORM\EntityManager; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Intl\Intl; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Intl\Intl; /* * Load or update the languages entities command */ class LoadAndUpdateLanguagesCommand extends Command { + public const INCLUDE_ANCIENT = 'include_ancient'; + + public const INCLUDE_REGIONAL_VERSION = 'include_regional'; + + // Array of ancien languages (to exclude) + private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga', + 'dum', 'enm', 'frm', 'gmh', 'mga', 'akk', 'phn', 'zxx', 'got', 'und', ]; + + private $availableLanguages; /** * @var EntityManager */ private $entityManager; - - private $availableLanguages; - + // The regional version of language are language with _ in the code // This array contains regional code to not exclude - private $regionalVersionToInclude = ["ro_MD"]; + private $regionalVersionToInclude = ['ro_MD']; - // Array of ancien languages (to exclude) - private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga", - "dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"]; - - const INCLUDE_REGIONAL_VERSION = 'include_regional'; - const INCLUDE_ANCIENT = 'include_ancient'; - /** * LoadCountriesCommand constructor. * - * @param EntityManager $entityManager * @param $availableLanguages */ public function __construct(EntityManager $entityManager, $availableLanguages) { - $this->entityManager=$entityManager; - $this->availableLanguages=$availableLanguages; + $this->entityManager = $entityManager; + $this->availableLanguages = $availableLanguages; parent::__construct(); } - - + /* * (non-PHPdoc) * @see \Symfony\Component\Console\Command\Command::configure() @@ -72,23 +60,24 @@ class LoadAndUpdateLanguagesCommand extends Command { $this ->setName('chill:main:languages:populate') - ->setDescription('Load or update languages in db. This command does not delete existing '. + ->setDescription('Load or update languages in db. This command does not delete existing ' . 'languages, but will update names according to available languages') ->addOption( - self::INCLUDE_REGIONAL_VERSION, - null, - InputOption::VALUE_NONE, - 'Include the regional languages. The regional languages are languages with code containing _ excepted ' - . implode(',', $this->regionalVersionToInclude) . '.') + self::INCLUDE_REGIONAL_VERSION, + null, + InputOption::VALUE_NONE, + 'Include the regional languages. The regional languages are languages with code containing _ excepted ' + . implode(',', $this->regionalVersionToInclude) . '.' + ) ->addOption( - self::INCLUDE_ANCIENT, - null, - InputOption::VALUE_NONE, - 'Include the ancient languages that are languages with code ' - . implode(', ', $this->ancientToExclude) . '.') - ; + self::INCLUDE_ANCIENT, + null, + InputOption::VALUE_NONE, + 'Include the ancient languages that are languages with code ' + . implode(', ', $this->ancientToExclude) . '.' + ); } - + /* * (non-PHPdoc) * @see \Symfony\Component\Console\Command\Command::execute() @@ -98,7 +87,7 @@ class LoadAndUpdateLanguagesCommand extends Command $em = $this->entityManager; $chillAvailableLanguages = $this->availableLanguages; $languageBundle = Intl::getLanguageBundle(); - $languages = array(); + $languages = []; foreach ($chillAvailableLanguages as $avLang) { $languages[$avLang] = $languageBundle->getLanguageNames($avLang); @@ -109,25 +98,25 @@ class LoadAndUpdateLanguagesCommand extends Command foreach ($languageCodes as $code) { $excludeCode = ( ( - ! $input->getOption(self::INCLUDE_REGIONAL_VERSION) + !$input->getOption(self::INCLUDE_REGIONAL_VERSION) and strpos($code, '_') and !in_array($code, $this->regionalVersionToInclude) ) or ( - ! $input->getOption(self::INCLUDE_ANCIENT) + !$input->getOption(self::INCLUDE_ANCIENT) and in_array($code, $this->ancientToExclude) ) ); $langageDB = $em->getRepository('ChillMainBundle:Language')->find($code); - if(! $excludeCode) { - if (! $langageDB) { + if (!$excludeCode) { + if (!$langageDB) { $langageDB = new \Chill\MainBundle\Entity\Language(); $langageDB->setId($code); $em->persist($langageDB); } - $avLangNames = array(); + $avLangNames = []; foreach ($chillAvailableLanguages as $avLang) { $avLangNames[$avLang] = $languages[$avLang][$code]; @@ -135,10 +124,10 @@ class LoadAndUpdateLanguagesCommand extends Command $langageDB->setName($avLangNames); } else { - if($langageDB) { + if ($langageDB) { $em->remove($langageDB); } - echo "Code excluded : ".$code." - ".$languageBundle->getLanguageName($code)."\n"; + echo 'Code excluded : ' . $code . ' - ' . $languageBundle->getLanguageName($code) . "\n"; } } diff --git a/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php b/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php index 036ad1de7..ab530a91e 100644 --- a/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php +++ b/src/Bundle/ChillMainBundle/Command/LoadCountriesCommand.php @@ -1,40 +1,66 @@ entityManager=$entityManager; - $this->availableLanguages=$availableLanguages; + $this->entityManager = $entityManager; + $this->availableLanguages = $availableLanguages; parent::__construct(); } - + + public static function prepareCountryList($languages) + { + $regionBundle = Intl::getRegionBundle(); + + foreach ($languages as $language) { + $countries[$language] = $regionBundle->getCountryNames($language); + } + + $countryEntities = []; + + foreach ($countries[$languages[0]] as $countryCode => $name) { + $names = []; + + foreach ($languages as $language) { + $names[$language] = $countries[$language][$countryCode]; + } + + $country = new \Chill\MainBundle\Entity\Country(); + $country->setName($names)->setCountryCode($countryCode); + $countryEntities[] = $country; + } + + return $countryEntities; + } + /* * (non-PHPdoc) * @see \Symfony\Component\Console\Command\Command::configure() @@ -42,10 +68,10 @@ class LoadCountriesCommand extends Command protected function configure() { $this->setName('chill:main:countries:populate') - ->setDescription('Load or update countries in db. This command does not delete existing countries, '. + ->setDescription('Load or update countries in db. This command does not delete existing countries, ' . 'but will update names according to available languages'); } - + /* * (non-PHPdoc) * @see \Symfony\Component\Console\Command\Command::execute() @@ -54,43 +80,18 @@ class LoadCountriesCommand extends Command { $countries = static::prepareCountryList($this->availableLanguages); $em = $this->entityManager; - - foreach($countries as $country) { + + foreach ($countries as $country) { $countryStored = $em->getRepository('ChillMainBundle:Country') - ->findOneBy(array('countryCode' => $country->getCountryCode())); - - if (NULL === $countryStored) { + ->findOneBy(['countryCode' => $country->getCountryCode()]); + + if (null === $countryStored) { $em->persist($country); } else { $countryStored->setName($country->getName()); } } - + $em->flush(); } - - public static function prepareCountryList($languages) - { - $regionBundle = Intl::getRegionBundle(); - - foreach ($languages as $language) { - $countries[$language] = $regionBundle->getCountryNames($language); - } - - $countryEntities = array(); - - foreach ($countries[$languages[0]] as $countryCode => $name) { - $names = array(); - - foreach ($languages as $language) { - $names[$language] = $countries[$language][$countryCode]; - } - - $country = new \Chill\MainBundle\Entity\Country(); - $country->setName($names)->setCountryCode($countryCode); - $countryEntities[] = $country; - } - - return $countryEntities; - } } diff --git a/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php b/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php index ba51db779..55b93352a 100644 --- a/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php +++ b/src/Bundle/ChillMainBundle/Command/LoadPostalCodesCommand.php @@ -1,58 +1,43 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Command; +use Chill\MainBundle\Entity\PostalCode; use Doctrine\ORM\EntityManager; +use Exception; +use RuntimeException; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Filesystem\Filesystem; -use Chill\MainBundle\Entity\PostalCode; use Symfony\Component\Validator\Validator\ValidatorInterface; /** - * Class LoadPostalCodesCommand - * - * @package Chill\MainBundle\Command - * @author Julien Fastré + * Class LoadPostalCodesCommand. */ class LoadPostalCodesCommand extends Command { - /** * @var EntityManager */ private $entityManager; - + /** * @var ValidatorInterface */ private $validator; - + /** * LoadPostalCodesCommand constructor. - * - * @param EntityManager $entityManager - * @param ValidatorInterface $validator */ public function __construct(EntityManager $entityManager, ValidatorInterface $validator) { @@ -60,167 +45,174 @@ class LoadPostalCodesCommand extends Command $this->validator = $validator; parent::__construct(); } - + protected function configure() { $this->setName('chill:main:postal-code:populate') - ->setDescription("Add the postal code from a csv file.") - ->setHelp("This script will try to avoid existing postal code " + ->setDescription('Add the postal code from a csv file.') + ->setHelp('This script will try to avoid existing postal code ' . "using the postal code and name. \n" - . "The CSV file must have the following columns: " - . "postal code, label, country code." - . "The CSV file should not have any header row.") - ->addArgument('csv_file', InputArgument::REQUIRED, "the path to " - . "the csv file. See the help for specifications.") - ->addOption( - 'delimiter', - 'd', - InputOption::VALUE_OPTIONAL, - "The delimiter character of the csv file", - ",") - ->addOption( - 'enclosure', - null, - InputOption::VALUE_OPTIONAL, - "The enclosure character of the csv file", - '"' - ) - ->addOption( - 'escape', - null, - InputOption::VALUE_OPTIONAL, - "The escape character of the csv file", - "\\" - ) - ; + . 'The CSV file must have the following columns: ' + . 'postal code, label, country code.' + . 'The CSV file should not have any header row.') + ->addArgument('csv_file', InputArgument::REQUIRED, 'the path to ' + . 'the csv file. See the help for specifications.') + ->addOption( + 'delimiter', + 'd', + InputOption::VALUE_OPTIONAL, + 'The delimiter character of the csv file', + ',' + ) + ->addOption( + 'enclosure', + null, + InputOption::VALUE_OPTIONAL, + 'The enclosure character of the csv file', + '"' + ) + ->addOption( + 'escape', + null, + InputOption::VALUE_OPTIONAL, + 'The escape character of the csv file', + '\\' + ); } - + protected function execute(InputInterface $input, OutputInterface $output) { try { $csv = $this->getCSVResource($input); - } catch (\RuntimeException $e) { - $output->writeln('Error during opening the csv file : '. - $e->getMessage().''); + } catch (RuntimeException $e) { + $output->writeln('Error during opening the csv file : ' . + $e->getMessage() . ''); } - + if ($output->getVerbosity() === OutputInterface::VERBOSITY_VERY_VERBOSE) { $output->writeln('The content of the file is ...'); $output->write(file_get_contents($input->getArgument('csv_file'))); } - + $num = 0; $line = 0; - - while (($row = fgetcsv( - $csv, - 0, - $input->getOption('delimiter'), - $input->getOption('enclosure'), - $input->getOption('escape'))) !== false) { - - try{ + + while ( + false !== ($row = fgetcsv( + $csv, + 0, + $input->getOption('delimiter'), + $input->getOption('enclosure'), + $input->getOption('escape') + )) + ) { + try { $this->addPostalCode($row, $output); - $num++; + ++$num; } catch (ExistingPostalCodeException $ex) { - $output->writeln(' on line '.$line.' : '.$ex->getMessage().''); + $output->writeln(' on line ' . $line . ' : ' . $ex->getMessage() . ''); } catch (CountryCodeNotFoundException $ex) { - $output->writeln(' on line '.$line.' : '.$ex->getMessage().''); + $output->writeln(' on line ' . $line . ' : ' . $ex->getMessage() . ''); } catch (PostalCodeNotValidException $ex) { - $output->writeln(' on line '.$line.' : '.$ex->getMessage().''); + $output->writeln(' on line ' . $line . ' : ' . $ex->getMessage() . ''); } - $line ++; + ++$line; } - + $this->entityManager->flush(); - - $output->writeln(''.$num.' were added !'); + + $output->writeln('' . $num . ' were added !'); } - + + private function addPostalCode($row, OutputInterface $output) + { + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $output->writeln('handling row: ' . $row[0] . ' | ' . $row[1] . ' | ' . $row[2]); + } + $em = $this->entityManager; + $country = $em + ->getRepository('ChillMainBundle:Country') + ->findOneBy(['countryCode' => $row[2]]); + + if (null === $country) { + throw new CountryCodeNotFoundException(sprintf( + 'The country with code %s is not found. Aborting to insert postal code with %s - %s', + $row[2], + $row[0], + $row[1] + )); + } + + // try to find an existing postal code + $existingPC = $em + ->getRepository('ChillMainBundle:PostalCode') + ->findBy(['code' => $row[0], 'name' => $row[1]]); + + if (count($existingPC) > 0) { + throw new ExistingPostalCodeException(sprintf( + 'A postal code with code : %s and name : %s already exists, skipping', + $row[0], + $row[1] + )); + } + + $postalCode = (new PostalCode()) + ->setCode($row[0]) + ->setName($row[1]) + ->setCountry($country); + + $errors = $this->validator->validate($postalCode); + + if ($errors->count() == 0) { + $em->persist($postalCode); + } else { + $msg = ''; + + foreach ($errors as $error) { + $msg .= ' ' . $error->getMessage(); + } + + throw new PostalCodeNotValidException($msg); + } + + if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { + $output->writeln(sprintf( + 'Creating postal code with code: %s, name: %s, countryCode: %s', + $postalCode->getCode(), + $postalCode->getName(), + $postalCode->getCountry()->getCountryCode() + )); + } + } + private function getCSVResource(InputInterface $input) { $fs = new Filesystem(); $filename = $input->getArgument('csv_file'); - + if (!$fs->exists($filename)) { - throw new \RuntimeException("The file does not exists or you do not " - . "have the right to read it."); + throw new RuntimeException('The file does not exists or you do not ' + . 'have the right to read it.'); } - + $resource = fopen($filename, 'r'); - - if ($resource == FALSE) { - throw new \RuntimeException("The file '$filename' could not be opened."); + + if (false == $resource) { + throw new RuntimeException("The file '{$filename}' could not be opened."); } - + return $resource; } - - private function addPostalCode($row, OutputInterface $output) - { - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $output->writeln('handling row: '. $row[0].' | '. $row[1].' | '. $row[2]); - } - $em = $this->entityManager; - $country = $em - ->getRepository('ChillMainBundle:Country') - ->findOneBy(array('countryCode' => $row[2])); - - if ($country === NULL) { - throw new CountryCodeNotFoundException(sprintf("The country with code %s is not found. Aborting to insert postal code with %s - %s", - $row[2], $row[0], $row[1])); - } - - // try to find an existing postal code - $existingPC = $em - ->getRepository('ChillMainBundle:PostalCode') - ->findBy(array('code' => $row[0], 'name' => $row[1])); - - if (count($existingPC) > 0) { - throw new ExistingPostalCodeException(sprintf("A postal code with code : %s and name : %s already exists, skipping", - $row[0], $row[1])); - } - - $postalCode = (new PostalCode()) - ->setCode($row[0]) - ->setName($row[1]) - ->setCountry($country) - ; - - $errors = $this->validator->validate($postalCode); - - if ($errors->count() == 0) { - $em->persist($postalCode); - } else { - $msg = ""; - foreach ($errors as $error) { - $msg .= " ".$error->getMessage(); - } - - throw new PostalCodeNotValidException($msg); - } - - - - if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) { - $output->writeln(sprintf('Creating postal code with code: %s, name: %s, countryCode: %s', - $postalCode->getCode(), $postalCode->getName(), $postalCode->getCountry()->getCountryCode())); - } - } } - -class ExistingPostalCodeException extends \Exception +class ExistingPostalCodeException extends Exception { - } -class CountryCodeNotFoundException extends \Exception +class CountryCodeNotFoundException extends Exception { - } -class PostalCodeNotValidException extends \Exception +class PostalCodeNotValidException extends Exception { - } diff --git a/src/Bundle/ChillMainBundle/Command/SetPasswordCommand.php b/src/Bundle/ChillMainBundle/Command/SetPasswordCommand.php index 9e00bd58f..78ab6ada0 100644 --- a/src/Bundle/ChillMainBundle/Command/SetPasswordCommand.php +++ b/src/Bundle/ChillMainBundle/Command/SetPasswordCommand.php @@ -1,101 +1,55 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Command; +use Chill\MainBundle\Entity\User; use Doctrine\ORM\EntityManager; +use LogicException; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Input\InputArgument; -use Chill\MainBundle\Entity\User; use Symfony\Component\Security\Core\Encoder\EncoderFactory; use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; -use Symfony\Component\Security\Core\Security; /** - * Class SetPasswordCommand - * - * @package Chill\MainBundle\Command - * @author Julien Fastré + * Class SetPasswordCommand. */ class SetPasswordCommand extends Command { - /** * @var EntityManager */ private $entityManager; - + /** * SetPasswordCommand constructor. - * - * @param EntityManager $entityManager */ public function __construct(EntityManager $entityManager) { $this->entityManager = $entityManager; parent::__construct(); } - - public function configure() - { - $this->setName('chill:user:set_password') - ->setDescription('set a password to user') - ->addArgument('username', InputArgument::REQUIRED, 'the user\'s ' - . 'username you want to change password') - ->addArgument('password', InputArgument::OPTIONAL, 'the new password') - ; - } - - public function execute(InputInterface $input, OutputInterface $output) - { - $user = $this->_getUser($input->getArgument('username')); - - if ($user === NULL) { - throw new \LogicException("The user with username '". - $input->getArgument('username')."' is not found"); - } - - $password = $input->getArgument('password'); - if ($password === NULL) { - $dialog = $this->getHelperSet()->get('dialog'); - $password = $dialog->askHiddenResponse($output, "the new password :" - . ""); - } - - $this->_setPassword($user, $password); - } - + public function _getUser($username) { return $this->entityManager ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => $username)); + ->findOneBy(['username' => $username]); } - + public function _setPassword(User $user, $password) { $defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000); $encoders = [ - User::class => $defaultEncoder + User::class => $defaultEncoder, ]; $encoderFactory = new EncoderFactory($encoders); $user->setPassword( @@ -103,4 +57,33 @@ class SetPasswordCommand extends Command ); $this->entityManager->flush($user); } + + public function configure() + { + $this->setName('chill:user:set_password') + ->setDescription('set a password to user') + ->addArgument('username', InputArgument::REQUIRED, 'the user\'s ' + . 'username you want to change password') + ->addArgument('password', InputArgument::OPTIONAL, 'the new password'); + } + + public function execute(InputInterface $input, OutputInterface $output) + { + $user = $this->_getUser($input->getArgument('username')); + + if (null === $user) { + throw new LogicException("The user with username '" . + $input->getArgument('username') . "' is not found"); + } + + $password = $input->getArgument('password'); + + if (null === $password) { + $dialog = $this->getHelperSet()->get('dialog'); + $password = $dialog->askHiddenResponse($output, 'the new password :' + . ''); + } + + $this->_setPassword($user, $password); + } } diff --git a/src/Bundle/ChillMainBundle/Controller/AddressController.php b/src/Bundle/ChillMainBundle/Controller/AddressController.php index 1aeb39062..7aa48c612 100644 --- a/src/Bundle/ChillMainBundle/Controller/AddressController.php +++ b/src/Bundle/ChillMainBundle/Controller/AddressController.php @@ -1,32 +1,37 @@ json($address); + default: throw new BadRequestException('Unsupported format'); } } - /** - * Get API Data for showing endpoint + * Get API Data for showing endpoint. * * @Route( * "/{_locale}/main/api/1.0/address-reference/{address_reference_id}/show.{_format}", * name="chill_main_address_reference_api_show" * ) * @ParamConverter("addressReference", options={"id": "address_reference_id"}) + * + * @param mixed $_format */ public function showAddressReference(AddressReference $addressReference, $_format): Response { @@ -55,9 +62,9 @@ class AddressController extends AbstractController switch ($_format) { case 'json': return $this->json($addressReference); + default: throw new BadRequestException('Unsupported format'); } - } } diff --git a/src/Bundle/ChillMainBundle/Controller/AdminController.php b/src/Bundle/ChillMainBundle/Controller/AdminController.php index cdb7796a3..0224fad69 100644 --- a/src/Bundle/ChillMainBundle/Controller/AdminController.php +++ b/src/Bundle/ChillMainBundle/Controller/AdminController.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Controller; @@ -24,31 +12,25 @@ namespace Chill\MainBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; /** - * Class AdminController - * - * @package Chill\MainBundle\Controller - * @author julien.fastre@champs-libres.coop - * @author marc@champs-libres.coop + * Class AdminController. */ class AdminController extends AbstractController { - - public function indexAction($menu = 'admin', - $header_title = 'views.Main.admin.index.header_title', - $page_title = 'views.Main.admin.index.page_title') { + public function configurationWarningsAction() + { + $alertManager = $this->get('chill_main.configuration_alert_manager'); + } + + public function indexAction( + $menu = 'admin', + $header_title = 'views.Main.admin.index.header_title', + $page_title = 'views.Main.admin.index.page_title' + ) { return $this->render('@ChillMain/Admin/layout.html.twig'); } - + public function indexPermissionsAction() { return $this->render('@ChillMain/Admin/layout_permissions.html.twig'); } - - public function configurationWarningsAction() - { - $alertManager = $this->get('chill_main.configuration_alert_manager'); - - - } - } diff --git a/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php b/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php index 310a36c60..3c30c18e8 100644 --- a/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php +++ b/src/Bundle/ChillMainBundle/Controller/AdminCountryCRUDController.php @@ -1,19 +1,20 @@ paginatorFactory = $paginator; } diff --git a/src/Bundle/ChillMainBundle/Controller/CenterController.php b/src/Bundle/ChillMainBundle/Controller/CenterController.php index c85140ff4..41c09a6ea 100644 --- a/src/Bundle/ChillMainBundle/Controller/CenterController.php +++ b/src/Bundle/ChillMainBundle/Controller/CenterController.php @@ -1,40 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillMainBundle:Center')->findAll(); - - return $this->render('@ChillMain/Center/index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new Center entity. - * */ public function createAction(Request $request) { @@ -47,71 +34,19 @@ class CenterController extends AbstractController $em->persist($center); $em->flush(); - return $this->redirect($this->generateUrl('admin_center_show', array('id' => $center->getId()))); + return $this->redirect($this->generateUrl('admin_center_show', ['id' => $center->getId()])); } - return $this->render('@ChillMain/Center/new.html.twig', array( + return $this->render('@ChillMain/Center/new.html.twig', [ 'entity' => $center, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a Center entity. - * - * @param Center $center The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Center $center) - { - $form = $this->createForm(CenterType::class, $center, array( - 'action' => $this->generateUrl('admin_center_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new Center entity. - * - */ - public function newAction() - { - $center = new Center(); - $form = $this->createCreateForm($center); - - return $this->render('@ChillMain/Center/new.html.twig', array( - 'entity' => $center, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Center entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $center = $em->getRepository('ChillMainBundle:Center')->find($id); - - if (!$center) { - throw $this->createNotFoundException('Unable to find Center entity.'); - } - - return $this->render('@ChillMain/Center/show.html.twig', array( - 'entity' => $center - )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing Center entity. * + * @param mixed $id */ public function editAction($id) { @@ -124,33 +59,65 @@ class CenterController extends AbstractController } $editForm = $this->createEditForm($center); - return $this->render('@ChillMain/Center/edit.html.twig', array( - 'entity' => $center, - 'edit_form' => $editForm->createView() - )); + + return $this->render('@ChillMain/Center/edit.html.twig', [ + 'entity' => $center, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a Center entity. - * - * @param Center $center The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Center $center) + * Lists all Center entities. + */ + public function indexAction() { - $form = $this->createForm(CenterType::class, $center, array( - 'action' => $this->generateUrl('admin_center_update', array('id' => $center->getId())), - 'method' => 'PUT', - )); + $em = $this->getDoctrine()->getManager(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + $entities = $em->getRepository('ChillMainBundle:Center')->findAll(); - return $form; + return $this->render('@ChillMain/Center/index.html.twig', [ + 'entities' => $entities, + ]); } + + /** + * Displays a form to create a new Center entity. + */ + public function newAction() + { + $center = new Center(); + $form = $this->createCreateForm($center); + + return $this->render('@ChillMain/Center/new.html.twig', [ + 'entity' => $center, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Center entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $center = $em->getRepository('ChillMainBundle:Center')->find($id); + + if (!$center) { + throw $this->createNotFoundException('Unable to find Center entity.'); + } + + return $this->render('@ChillMain/Center/show.html.twig', [ + 'entity' => $center, + ]); + } + /** * Edits an existing Center entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -168,12 +135,50 @@ class CenterController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('admin_center_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('admin_center_edit', ['id' => $id])); } - return $this->render('@ChillMain/Center/edit.html.twig', array( - 'entity' => $center, - 'edit_form' => $editForm->createView() - )); + return $this->render('@ChillMain/Center/edit.html.twig', [ + 'entity' => $center, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a Center entity. + * + * @param Center $center The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(Center $center) + { + $form = $this->createForm(CenterType::class, $center, [ + 'action' => $this->generateUrl('admin_center_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a Center entity. + * + * @param Center $center The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Center $center) + { + $form = $this->createForm(CenterType::class, $center, [ + 'action' => $this->generateUrl('admin_center_update', ['id' => $center->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillMainBundle/Controller/DefaultController.php b/src/Bundle/ChillMainBundle/Controller/DefaultController.php index 8ad6d8d3a..0670f2365 100644 --- a/src/Bundle/ChillMainBundle/Controller/DefaultController.php +++ b/src/Bundle/ChillMainBundle/Controller/DefaultController.php @@ -1,23 +1,27 @@ isGranted('ROLE_ADMIN')) { - return $this->redirectToRoute('chill_main_admin_central', [], 302); } - + return $this->render('@ChillMain/layout.html.twig'); } @@ -25,62 +29,61 @@ class DefaultController extends AbstractController { return $this->redirect($this->generateUrl('chill_main_homepage')); } - + public function testAction() { return $this->render('@ChillMain/Tabs/index.html.twig', [ 'tabs' => [ 'test1' => [ [ - 'name' => "Link 1", - 'content' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.", + 'name' => 'Link 1', + 'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.', ], [ - 'name' => "Link 2", - 'content' => "Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.", + 'name' => 'Link 2', + 'content' => 'Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.', ], [ - 'name' => "Link 3", - 'content' => "In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.", + 'name' => 'Link 3', + 'content' => 'In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.', ], [ - 'name' => "Link 4", - 'content' => "Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.", + 'name' => 'Link 4', + 'content' => 'Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.', ], [ - 'name' => "Link 5", - 'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.", - ] + 'name' => 'Link 5', + 'content' => 'Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.', + ], ], 'test2' => [ [ - 'name' => "Link 1", - 'link' => "http://localhost", - 'content' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.", + 'name' => 'Link 1', + 'link' => 'http://localhost', + 'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae auctor eu augue ut. Elementum nisi quis eleifend quam. Faucibus purus in massa tempor nec. Turpis massa sed elementum tempus egestas sed sed risus. Etiam sit amet nisl purus in mollis nunc sed id. Enim nunc faucibus a pellentesque sit amet porttitor eget. Risus nec feugiat in fermentum posuere. Augue mauris augue neque gravida. Sollicitudin aliquam ultrices sagittis orci a scelerisque purus semper eget. Id leo in vitae turpis massa sed elementum tempus egestas. Mauris commodo quis imperdiet massa. Fames ac turpis egestas integer eget aliquet nibh praesent. Urna porttitor rhoncus dolor purus non enim praesent elementum. Donec enim diam vulputate ut pharetra sit. Auctor neque vitae tempus quam. Mattis rhoncus urna neque viverra justo nec ultrices.', ], [ - 'name' => "Link 2", + 'name' => 'Link 2', //'link' => "http://localhost", - 'content' => "Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.", + 'content' => 'Dui sapien eget mi proin sed libero. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Turpis nunc eget lorem dolor. Phasellus egestas tellus rutrum tellus. Diam sit amet nisl suscipit adipiscing bibendum est ultricies integer. Duis ultricies lacus sed turpis tincidunt id. Nisl suscipit adipiscing bibendum est ultricies integer. Elementum nibh tellus molestie nunc non blandit massa enim. Faucibus in ornare quam viverra orci sagittis eu. Neque volutpat ac tincidunt vitae semper quis lectus nulla. Accumsan sit amet nulla facilisi morbi. Leo vel fringilla est ullamcorper eget nulla facilisi etiam dignissim. Amet est placerat in egestas erat imperdiet sed euismod. Quis auctor elit sed vulputate mi. Mauris nunc congue nisi vitae suscipit tellus mauris a diam. At volutpat diam ut venenatis. Facilisis gravida neque convallis a cras semper.', ], [ - 'name' => "Link 3", + 'name' => 'Link 3', //'link' => "http://localhost", - 'content' => "In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.", + 'content' => 'In ornare quam viverra orci sagittis eu volutpat. Ac tincidunt vitae semper quis lectus nulla at volutpat. Placerat duis ultricies lacus sed turpis tincidunt. Augue interdum velit euismod in pellentesque. Felis eget nunc lobortis mattis aliquam. Volutpat lacus laoreet non curabitur gravida arcu. Gravida cum sociis natoque penatibus et magnis dis parturient montes. Nisl pretium fusce id velit ut tortor. Nunc scelerisque viverra mauris in aliquam sem fringilla ut. Magna eget est lorem ipsum dolor sit. Non consectetur a erat nam at lectus urna. Eget est lorem ipsum dolor sit amet consectetur adipiscing elit. Sed velit dignissim sodales ut.', ], [ - 'name' => "Link 4", - 'link' => "http://localhost", + 'name' => 'Link 4', + 'link' => 'http://localhost', //'content' => "Ut tellus elementum sagittis vitae et. Vitae purus faucibus ornare suspendisse sed nisi lacus sed viverra. Hendrerit gravida rutrum quisque non tellus orci ac auctor augue. Eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus. Dictumst quisque sagittis purus sit. Suspendisse sed nisi lacus sed viverra. Pretium quam vulputate dignissim suspendisse in est ante. Id eu nisl nunc mi ipsum. Ut venenatis tellus in metus vulputate. Ut morbi tincidunt augue interdum velit euismod.", ], [ - 'name' => "Link 5", + 'name' => 'Link 5', //'link' => "http://localhost", - 'content' => "Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.", - ] - ] - ] + 'content' => 'Vel elit scelerisque mauris pellentesque pulvinar. Ornare suspendisse sed nisi lacus sed viverra tellus. Massa tincidunt dui ut ornare lectus sit. Congue nisi vitae suscipit tellus mauris a diam. At auctor urna nunc id cursus metus aliquam. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Mattis aliquam faucibus purus in massa tempor nec feugiat. Et leo duis ut diam quam. Auctor augue mauris augue neque. Purus ut faucibus pulvinar elementum integer enim neque volutpat. Scelerisque felis imperdiet proin fermentum leo. Diam sit amet nisl suscipit adipiscing bibendum est ultricies. Consectetur libero id faucibus nisl tincidunt. Vel fringilla est ullamcorper eget nulla facilisi. Pharetra diam sit amet nisl suscipit adipiscing. Dignissim diam quis enim lobortis. Auctor eu augue ut lectus arcu bibendum at varius.', + ], + ], + ], ]); } - } diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 71f6c0543..250429def 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -1,86 +1,68 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Controller; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; +use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\FormatterType; -use Symfony\Component\Form\Extension\Core\Type\FormType; use Chill\MainBundle\Form\Type\Export\PickCenterType; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Chill\MainBundle\Export\ExportManager; -use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Session\SessionInterface; -use Symfony\Component\Form\FormFactoryInterface; use Chill\MainBundle\Redis\ChillRedis; +use LogicException; +use Psr\Log\LoggerInterface; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Translation\TranslatorInterface; +use function serialize; +use function unserialize; + /** * Class ExportController * Controller used for exporting data. - * - * @package Chill\MainBundle\Controller */ class ExportController extends AbstractController { - /** - * * @var ExportManager */ protected $exportManager; - + /** - * - * @var LoggerInterface - */ - protected $logger; - - /** - * - * @var SessionInterface - */ - protected $session; - - /** - * * @var FormFactoryInterface */ protected $formFactory; - + + /** + * @var LoggerInterface + */ + protected $logger; + /** - * * @var ChillRedis */ protected $redis; - + + /** + * @var SessionInterface + */ + protected $session; + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( ChillRedis $chillRedis, ExportManager $exportManager, @@ -97,11 +79,63 @@ class ExportController extends AbstractController $this->translator = $translator; } - + public function downloadResultAction(Request $request, $alias) + { + /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ + $exportManager = $this->exportManager; + $key = $request->query->get('key', null); + + [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key); + + $formatterAlias = $exportManager->getFormatterAlias($dataExport['export']); + + if (null !== $formatterAlias) { + $formater = $exportManager->getFormatter($formatterAlias); + } else { + $formater = null; + } + + $viewVariables = [ + 'alias' => $alias, + 'export' => $exportManager->getExport($alias), + ]; + + if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) { + // due to a bug in php, we add the mime type in the download view + $viewVariables['mime_type'] = 'text/csv'; + } + + return $this->render('@ChillMain/Export/download.html.twig', $viewVariables); + } + /** - * Render the list of available exports + * Generate a report. + * + * This action must work with GET queries. + * + * @param string $alias + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function generateAction(Request $request, $alias) + { + /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ + $exportManager = $this->exportManager; + $key = $request->query->get('key', null); + + [$dataCenters, $dataExport, $dataFormatter] = $this->rebuildData($key); + + return $exportManager->generate( + $alias, + $dataCenters['centers'], + $dataExport['export'], + null !== $dataFormatter ? $dataFormatter['formatter'] : [] + ); + } + + /** + * Render the list of available exports. * - * @param Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function indexAction(Request $request) @@ -109,14 +143,14 @@ class ExportController extends AbstractController $exportManager = $this->exportManager; $exports = $exportManager->getExportsGrouped(true); - - return $this->render('@ChillMain/Export/layout.html.twig', array( - 'grouped_exports' => $exports - )); + + return $this->render('@ChillMain/Export/layout.html.twig', [ + 'grouped_exports' => $exports, + ]); } /** - * handle the step to build a query for an export + * handle the step to build a query for an export. * * This action has three steps : * @@ -129,6 +163,7 @@ class ExportController extends AbstractController * * @param string $request * @param Request $alias + * * @return \Symfony\Component\HttpFoundation\Response */ public function newAction(Request $request, $alias) @@ -137,7 +172,7 @@ class ExportController extends AbstractController $exportManager = $this->exportManager; $export = $exportManager->getExport($alias); - if ($exportManager->isGrantedForElement($export) === FALSE) { + if ($exportManager->isGrantedForElement($export) === false) { throw $this->createAccessDeniedException('The user does not have access to this export'); } @@ -146,77 +181,87 @@ class ExportController extends AbstractController switch ($step) { case 'centers': return $this->selectCentersStep($request, $export, $alias); + case 'export': return $this->exportFormStep($request, $export, $alias); + break; + case 'formatter': return $this->formatterFormStep($request, $export, $alias); + break; + case 'generate': return $this->forwardToGenerate($request, $export, $alias); + break; + default: - throw $this->createNotFoundException("The given step '$step' is invalid"); + throw $this->createNotFoundException("The given step '{$step}' is invalid"); } } /** - * - * @param Request $request - * @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export + * create a form to show on different steps. + * * @param string $alias - * @return Response - * @throws type + * @param array $data the data from previous step. Required for steps 'formatter' and 'generate_formatter' + * @param mixed $step + * + * @return \Symfony\Component\Form\Form */ - protected function selectCentersStep(Request $request, $export, $alias) + protected function createCreateFormExport($alias, $step, $data = []) { /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ $exportManager = $this->exportManager; + $isGenerate = strpos($step, 'generate_') === 0; - $form = $this->createCreateFormExport($alias, 'centers'); + $builder = $this->formFactory + ->createNamedBuilder(null, FormType::class, [], [ + 'method' => $isGenerate ? 'GET' : 'POST', + 'csrf_protection' => $isGenerate ? false : true, + ]); - if ($request->getMethod() === 'POST') { - $form->handleRequest($request); - if ($form->isValid()) { - $this->logger->debug('form centers is valid', array( - 'location' => __METHOD__)); - - $data = $form->getData(); - - // check ACL - if ($exportManager->isGrantedForElement($export, NULL, - $exportManager->getPickedCenters($data['centers'])) === FALSE) { - throw $this->createAccessDeniedException('you do not have ' - . 'access to this export for those centers'); - } - - $this->session->set('centers_step_raw', - $request->request->all()); - $this->session->set('centers_step', $data); - - return $this->redirectToRoute('chill_main_export_new', array( - 'step' => $this->getNextStep('centers', $export), - 'alias' => $alias - )); - - } + if ('centers' === $step or 'generate_centers' === $step) { + $builder->add('centers', PickCenterType::class, [ + 'export_alias' => $alias, + ]); } - return $this->render('@ChillMain/Export/new_centers_step.html.twig', - array( - 'form' => $form->createView(), - 'export' => $export - )); + if ('export' === $step or 'generate_export' === $step) { + $builder->add('export', ExportType::class, [ + 'export_alias' => $alias, + 'picked_centers' => $exportManager->getPickedCenters($data['centers']), + ]); + } + + if ('formatter' === $step or 'generate_formatter' === $step) { + $builder->add('formatter', FormatterType::class, [ + 'formatter_alias' => $exportManager + ->getFormatterAlias($data['export']), + 'export_alias' => $alias, + 'aggregator_aliases' => $exportManager + ->getUsedAggregatorsAliases($data['export']), + ]); + } + + $builder->add('submit', SubmitType::class, [ + 'label' => 'Generate', + ]); + + return $builder->getForm(); } /** - * Render the export form + * Render the export form. * * When the method is POST, the form is stored if valid, and a redirection * is done to next step. * * @param string $alias - * @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export + * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export + * * @return \Symfony\Component\HttpFoundation\Response */ protected function exportFormStep(Request $request, $export, $alias) @@ -226,12 +271,11 @@ class ExportController extends AbstractController // check we have data from the previous step (export step) $data = $this->session->get('centers_step', null); - if ($data === null) { - - return $this->redirectToRoute('chill_main_export_new', array( - 'step' => $this->getNextStep('export', $export, true), - 'alias' => $alias - )); + if (null === $data) { + return $this->redirectToRoute('chill_main_export_new', [ + 'step' => $this->getNextStep('export', $export, true), + 'alias' => $alias, + ]); } $export = $exportManager->getExport($alias); @@ -240,123 +284,36 @@ class ExportController extends AbstractController if ($request->getMethod() === 'POST') { $form->handleRequest($request); - if ($form->isValid()) { - $this->logger->debug('form export is valid', array( - 'location' => __METHOD__)); + if ($form->isValid()) { + $this->logger->debug('form export is valid', [ + 'location' => __METHOD__, ]); // store data for reusing in next steps $data = $form->getData(); - $this->session->set('export_step_raw', - $request->request->all()); + $this->session->set( + 'export_step_raw', + $request->request->all() + ); $this->session->set('export_step', $data); //redirect to next step return $this->redirect( - $this->generateUrl('chill_main_export_new', array( - 'step' => $this->getNextStep('export', $export), - 'alias' => $alias - ))); - } else { - $this->logger->debug('form export is invalid', array( - 'location' => __METHOD__)); + $this->generateUrl('chill_main_export_new', [ + 'step' => $this->getNextStep('export', $export), + 'alias' => $alias, + ]) + ); } + $this->logger->debug('form export is invalid', [ + 'location' => __METHOD__, ]); } - return $this->render('@ChillMain/Export/new.html.twig', array( + return $this->render('@ChillMain/Export/new.html.twig', [ 'form' => $form->createView(), 'export_alias' => $alias, - 'export' => $export - )); - } - - /** - * create a form to show on different steps. - * - * @param string $alias - * @param string $step, can either be 'export', 'formatter', 'generate_export' or 'generate_formatter' (last two are used by generate action) - * @param array $data the data from previous step. Required for steps 'formatter' and 'generate_formatter' - * @return \Symfony\Component\Form\Form - */ - protected function createCreateFormExport($alias, $step, $data = array()) - { - /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ - $exportManager = $this->exportManager; - $isGenerate = strpos($step, 'generate_') === 0; - - $builder = $this->formFactory - ->createNamedBuilder(null, FormType::class, array(), array( - 'method' => $isGenerate ? 'GET' : 'POST', - 'csrf_protection' => $isGenerate ? false : true, - )); - - if ($step === 'centers' or $step === 'generate_centers') { - $builder->add('centers', PickCenterType::class, array( - 'export_alias' => $alias - )); - } - - if ($step === 'export' or $step === 'generate_export') { - $builder->add('export', ExportType::class, array( - 'export_alias' => $alias, - 'picked_centers' => $exportManager->getPickedCenters($data['centers']) - )); - } - - if ($step === 'formatter' or $step === 'generate_formatter') { - $builder->add('formatter', FormatterType::class, array( - 'formatter_alias' => $exportManager - ->getFormatterAlias($data['export']), - 'export_alias' => $alias, - 'aggregator_aliases' => $exportManager - ->getUsedAggregatorsAliases($data['export']) - )); - } - - $builder->add('submit', SubmitType::class, array( - 'label' => 'Generate' - )); - - return $builder->getForm(); - } - - /** - * get the next step. If $reverse === true, the previous step is returned. - * - * This method provides a centralized way of handling next/previous step. - * - * @param string $step the current step - * @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export - * @param boolean $reverse set to true to get the previous step - * @return string the next/current step - * @throws \LogicException if there is no step before or after the given step - */ - private function getNextStep($step, $export, $reverse = false) - { - switch($step) { - case 'centers': - if ($reverse !== false) { - throw new \LogicException("there is no step before 'export'"); - } - return 'export'; - case 'export': - if ($export instanceof \Chill\MainBundle\Export\ExportInterface) { - return $reverse ? 'centers' : 'formatter'; - } elseif ($export instanceof \Chill\MainBundle\Export\DirectExportInterface) { - return $reverse ? 'centers' : 'generate'; - } - - case 'formatter' : - return $reverse ? 'export' : 'generate'; - case 'generate' : - if ($reverse === false) { - throw new \LogicException("there is no step after 'generate'"); - } - return 'formatter'; - - default: - throw new \LogicException("the step $step is not defined."); - } + 'export' => $export, + ]); } /** @@ -365,23 +322,21 @@ class ExportController extends AbstractController * If the form is posted and valid, store the data in session and * redirect to the next step. * - * @param Request $request - * @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export + * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export * @param string $alias + * * @return \Symfony\Component\HttpFoundation\Response */ protected function formatterFormStep(Request $request, $export, $alias) { - // check we have data from the previous step (export step) $data = $this->session->get('export_step', null); - if ($data === null) { - - return $this->redirectToRoute('chill_main_export_new', array( - 'step' => $this->getNextStep('formatter', $export, true), - 'alias' => $alias - )); + if (null === $data) { + return $this->redirectToRoute('chill_main_export_new', [ + 'step' => $this->getNextStep('formatter', $export, true), + 'alias' => $alias, + ]); } $form = $this->createCreateFormExport($alias, 'formatter', $data); @@ -392,23 +347,29 @@ class ExportController extends AbstractController if ($form->isValid()) { $dataFormatter = $form->getData(); $this->session->set('formatter_step', $dataFormatter); - $this->session->set('formatter_step_raw', - $request->request->all()); + $this->session->set( + 'formatter_step_raw', + $request->request->all() + ); //redirect to next step - return $this->redirect($this->generateUrl('chill_main_export_new', - array( - 'alias' => $alias, - 'step' => $this->getNextStep('formatter', $export) - ))); + return $this->redirect($this->generateUrl( + 'chill_main_export_new', + [ + 'alias' => $alias, + 'step' => $this->getNextStep('formatter', $export), + ] + )); } } - return $this->render('@ChillMain/Export/new_formatter_step.html.twig', - array( - 'form' => $form->createView(), - 'export' => $export - )); + return $this->render( + '@ChillMain/Export/new_formatter_step.html.twig', + [ + 'form' => $form->createView(), + 'export' => $export, + ] + ); } /** @@ -417,9 +378,9 @@ class ExportController extends AbstractController * * The data from previous steps is removed from session. * - * @param Request $request - * @param \Chill\MainBundle\Export\ExportInterface|\Chill\MainBundle\Export\DirectExportInterface $export + * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export * @param string $alias + * * @return \Symfony\Component\HttpFoundation\RedirectResponse */ protected function forwardToGenerate(Request $request, $export, $alias) @@ -428,22 +389,22 @@ class ExportController extends AbstractController $dataFormatter = $this->session->get('formatter_step_raw', null); $dataExport = $this->session->get('export_step_raw', null); - if ($dataFormatter === NULL and $export instanceof \Chill\MainBundle\Export\ExportInterface) { - return $this->redirectToRoute('chill_main_export_new', array( - 'alias' => $alias, 'step' => $this->getNextStep('generate', $export, true) - )); + if (null === $dataFormatter and $export instanceof \Chill\MainBundle\Export\ExportInterface) { + return $this->redirectToRoute('chill_main_export_new', [ + 'alias' => $alias, 'step' => $this->getNextStep('generate', $export, true), + ]); } - + $parameters = [ - 'formatter' => $dataFormatter ?? [], - 'export' => $dataExport ?? [], - 'centers' => $dataCenters ?? [], - 'alias' => $alias - ]; + 'formatter' => $dataFormatter ?? [], + 'export' => $dataExport ?? [], + 'centers' => $dataCenters ?? [], + 'alias' => $alias, + ]; unset($parameters['_token']); $key = md5(uniqid(rand(), false)); - - $this->redis->setEx($key, 3600, \serialize($parameters)); + + $this->redis->setEx($key, 3600, serialize($parameters)); // remove data from session $this->session->remove('export_step_raw'); @@ -451,56 +412,30 @@ class ExportController extends AbstractController $this->session->remove('formatter_step_raw'); $this->session->remove('formatter_step'); - return $this->redirectToRoute('chill_main_export_download', [ 'key' => $key, 'alias' => $alias ]); + return $this->redirectToRoute('chill_main_export_download', ['key' => $key, 'alias' => $alias]); } - /** - * Generate a report. - * - * This action must work with GET queries. - * - * @param Request $request - * @param string $alias - * @return \Symfony\Component\HttpFoundation\Response - */ - public function generateAction(Request $request, $alias) - { - /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ - $exportManager = $this->exportManager; - $key = $request->query->get('key', null); - - list($dataCenters, $dataExport, $dataFormatter) = $this->rebuildData($key); - - $r = $exportManager->generate( - $alias, - $dataCenters['centers'], - $dataExport['export'], - $dataFormatter !== NULL ? $dataFormatter['formatter'] : [] - ); - - return $r; - } - protected function rebuildData($key) { - if ($key === NULL) { - throw $this->createNotFoundException("key does not exists"); + if (null === $key) { + throw $this->createNotFoundException('key does not exists'); } - + if ($this->redis->exists($key) !== 1) { - $this->addFlash('error', $this->translator->trans("This report is not available any more")); - throw $this->createNotFoundException("key does not exists"); + $this->addFlash('error', $this->translator->trans('This report is not available any more')); + + throw $this->createNotFoundException('key does not exists'); } - + $serialized = $this->redis->get($key); - - if ($serialized === false) { - throw new \LogicException("the key could not be reached from redis"); + + if (false === $serialized) { + throw new LogicException('the key could not be reached from redis'); } - - $rawData = \unserialize($serialized); + + $rawData = unserialize($serialized); $alias = $rawData['alias']; - + $formCenters = $this->createCreateFormExport($alias, 'generate_centers'); $formCenters->submit($rawData['centers']); $dataCenters = $formCenters->getData(); @@ -510,40 +445,121 @@ class ExportController extends AbstractController $dataExport = $formExport->getData(); if (count($rawData['formatter']) > 0) { - $formFormatter = $this->createCreateFormExport($alias, 'generate_formatter', - $dataExport); + $formFormatter = $this->createCreateFormExport( + $alias, + 'generate_formatter', + $dataExport + ); $formFormatter->submit($rawData['formatter']); $dataFormatter = $formFormatter->getData(); } - + return [$dataCenters, $dataExport, $dataFormatter ?? null]; } - public function downloadResultAction(Request $request, $alias) - { + /** + * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export + * @param string $alias + * + * @throws type + * + * @return Response + */ + protected function selectCentersStep(Request $request, $export, $alias) + { /* @var $exportManager \Chill\MainBundle\Export\ExportManager */ $exportManager = $this->exportManager; - $key = $request->query->get('key', null); - - list($dataCenters, $dataExport, $dataFormatter) = $this->rebuildData($key); - - $formatterAlias = $exportManager->getFormatterAlias($dataExport['export']); - if ($formatterAlias !== null) { - $formater = $exportManager->getFormatter($formatterAlias); - } else { - $formater = null; + + $form = $this->createCreateFormExport($alias, 'centers'); + + if ($request->getMethod() === 'POST') { + $form->handleRequest($request); + + if ($form->isValid()) { + $this->logger->debug('form centers is valid', [ + 'location' => __METHOD__, ]); + + $data = $form->getData(); + + // check ACL + if ( + $exportManager->isGrantedForElement( + $export, + null, + $exportManager->getPickedCenters($data['centers']) + ) === false + ) { + throw $this->createAccessDeniedException('you do not have ' + . 'access to this export for those centers'); + } + + $this->session->set( + 'centers_step_raw', + $request->request->all() + ); + $this->session->set('centers_step', $data); + + return $this->redirectToRoute('chill_main_export_new', [ + 'step' => $this->getNextStep('centers', $export), + 'alias' => $alias, + ]); + } } - - $viewVariables = [ - 'alias' => $alias, - 'export' => $exportManager->getExport($alias) - ]; - - if ($formater instanceof \Chill\MainBundle\Export\Formatter\CSVListFormatter) { - // due to a bug in php, we add the mime type in the download view - $viewVariables['mime_type'] = 'text/csv'; + + return $this->render( + '@ChillMain/Export/new_centers_step.html.twig', + [ + 'form' => $form->createView(), + 'export' => $export, + ] + ); + } + + /** + * get the next step. If $reverse === true, the previous step is returned. + * + * This method provides a centralized way of handling next/previous step. + * + * @param string $step the current step + * @param \Chill\MainBundle\Export\DirectExportInterface|\Chill\MainBundle\Export\ExportInterface $export + * @param bool $reverse set to true to get the previous step + * + * @throws LogicException if there is no step before or after the given step + * + * @return string the next/current step + */ + private function getNextStep($step, $export, $reverse = false) + { + switch ($step) { + case 'centers': + if (false !== $reverse) { + throw new LogicException("there is no step before 'export'"); + } + + return 'export'; + + case 'export': + if ($export instanceof \Chill\MainBundle\Export\ExportInterface) { + return $reverse ? 'centers' : 'formatter'; + } + + if ($export instanceof \Chill\MainBundle\Export\DirectExportInterface) { + return $reverse ? 'centers' : 'generate'; + } + + // no break + case 'formatter': + return $reverse ? 'export' : 'generate'; + + case 'generate': + if (false === $reverse) { + throw new LogicException("there is no step after 'generate'"); + } + + return 'formatter'; + + default: + throw new LogicException("the step {$step} is not defined."); } - - return $this->render("@ChillMain/Export/download.html.twig", $viewVariables); } } diff --git a/src/Bundle/ChillMainBundle/Controller/LoginController.php b/src/Bundle/ChillMainBundle/Controller/LoginController.php index 920ce22c3..09b14fb44 100644 --- a/src/Bundle/ChillMainBundle/Controller/LoginController.php +++ b/src/Bundle/ChillMainBundle/Controller/LoginController.php @@ -1,5 +1,12 @@ helper = $helper; } - + /** - * Show a login form - * - * @param Request $request + * Show a login form. + * * @return Response */ public function loginAction(Request $request) { - - return $this->render('@ChillMain/Login/login.html.twig', array( + return $this->render('@ChillMain/Login/login.html.twig', [ 'last_username' => $this->helper->getLastUsername(), - 'error' => $this->helper->getLastAuthenticationError() - )); + 'error' => $this->helper->getLastAuthenticationError(), + ]); } - + public function LoginCheckAction(Request $request) { - } - } diff --git a/src/Bundle/ChillMainBundle/Controller/MenuController.php b/src/Bundle/ChillMainBundle/Controller/MenuController.php index 8820c8356..0f87217eb 100644 --- a/src/Bundle/ChillMainBundle/Controller/MenuController.php +++ b/src/Bundle/ChillMainBundle/Controller/MenuController.php @@ -1,23 +1,28 @@ render($layout, array( + return $this->render($layout, [ 'menu_composer' => $this->get('chill.main.menu_composer'), 'menu' => $menu, 'args' => $args, - 'activeRouteKey' => $activeRouteKey - )); + 'activeRouteKey' => $activeRouteKey, + ]); } } diff --git a/src/Bundle/ChillMainBundle/Controller/PasswordController.php b/src/Bundle/ChillMainBundle/Controller/PasswordController.php index a5cab5b9f..e8139c4cf 100644 --- a/src/Bundle/ChillMainBundle/Controller/PasswordController.php +++ b/src/Bundle/ChillMainBundle/Controller/PasswordController.php @@ -1,72 +1,71 @@ recoverPasswordHelper = $recoverPasswordHelper; $this->eventDispatcher = $eventDispatcher; } - + + /** + * @return Response + */ + public function changeConfirmedAction() + { + return $this->render('@ChillMain/Password/recover_password_changed.html.twig'); + } + + /** + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function recoverAction(Request $request) + { + if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) { + return new Response($this->translator->trans('You are not allowed ' + . 'to try to recover password, due to mitigating possible ' + . 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN); + } + + $query = $request->query; + $username = $query->get(TokenManager::USERNAME_CANONICAL); + $hash = $query->getAlnum(TokenManager::HASH); + $token = $query->getAlnum(TokenManager::TOKEN); + $timestamp = $query->getInt(TokenManager::TIMESTAMP); + $user = $this->getDoctrine()->getRepository(User::class) + ->findOneByUsernameCanonical($username); + + if (null === $user) { + $this->eventDispatcher->dispatch( + PasswordRecoverEvent::INVALID_TOKEN, + new PasswordRecoverEvent($token, null, $request->getClientIp()) + ); + + throw $this->createNotFoundException(sprintf('User %s not found', $username)); + } + + if (true !== $this->tokenManager->verify($hash, $token, $user, $timestamp)) { + $this->eventDispatcher->dispatch( + PasswordRecoverEvent::INVALID_TOKEN, + new PasswordRecoverEvent($token, $user, $request->getClientIp()) + ); + + return new Response('Invalid token', Response::HTTP_FORBIDDEN); + } + + $form = $this->passwordForm($user); + $form->remove('actual_password'); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $password = $form->get('new_password')->getData(); + $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); + // logging for prod + $this + ->chillLogger + ->notice( + 'setting new password for user', + [ + 'user' => $user->getUsername(), + ] + ); + + $this->getDoctrine()->getManager()->flush(); + + return $this->redirectToRoute('password_request_recover_changed'); + } + + return $this->render('@ChillMain/Password/recover_password_form.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * @throws \Doctrine\ORM\NoResultException + * @throws \Doctrine\ORM\NonUniqueResultException + * + * @return Response|\Symfony\Component\HttpFoundation\RedirectResponse + */ + public function requestRecoverAction(Request $request) + { + if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) { + return new Response($this->translator->trans('You are not allowed ' + . 'to try to recover password, due to mitigating possible ' + . 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN); + } + + $form = $this->requestRecoverForm(); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + /* @var $qb \Doctrine\ORM\QueryBuilder */ + $qb = $this->getDoctrine()->getManager() + ->createQueryBuilder(); + $qb->select('u') + ->from(User::class, 'u') + ->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))')) + ->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))')) + ->setParameter('pattern', $form->get('username_or_email')->getData()); + + $user = $qb->getQuery()->getSingleResult(); + + if (empty($user->getEmail())) { + $this->addFlash('error', $this->translator->trans('This account does not have an email address. ' + . 'Please ask your administrator to renew your password.')); + } else { + if (false === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN, $user)) { + return new Response($this->translator->trans('You are not allowed ' + . 'to try to recover password, due to mitigating possible ' + . 'attack. Try to contact your system administrator'), Response::HTTP_FORBIDDEN); + } + + $this->recoverPasswordHelper->sendRecoverEmail( + $user, + (new DateTimeImmutable('now'))->add(new DateInterval('PT30M')) + ); + + // logging for prod + $this + ->chillLogger + ->notice( + 'Sending an email for password recovering', + [ + 'user' => $user->getUsername(), + ] + ); + + $this->eventDispatcher->dispatch( + PasswordRecoverEvent::ASK_TOKEN_SUCCESS, + new PasswordRecoverEvent(null, $user, $request->getClientIp()) + ); + + return $this->redirectToRoute('password_request_recover_confirm'); + } + } elseif ($form->isSubmitted() && false === $form->isValid()) { + $this->eventDispatcher->dispatch( + PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM, + new PasswordRecoverEvent(null, null, $request->getClientIp()) + ); + } + + return $this->render('@ChillMain/Password/request_recover_password.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * @return Response + */ + public function requestRecoverConfirmAction() + { + return $this->render('@ChillMain/Password/request_recover_password_confirm.html.twig'); + } + /** - * @param Request $request * @return Response */ public function UserPasswordAction(Request $request) @@ -107,11 +260,11 @@ class PasswordController extends AbstractController ->chillLogger ->notice( 'update password for an user', - array( - 'method' => $request->getMethod(), - 'user' => $user->getUsername() - ) - ); + [ + 'method' => $request->getMethod(), + 'user' => $user->getUsername(), + ] + ); $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); @@ -119,186 +272,16 @@ class PasswordController extends AbstractController $em->flush(); $this->addFlash('success', $this->translator->trans('Password successfully updated!')); - - return $this->redirectToRoute('change_my_password'); + return $this->redirectToRoute('change_my_password'); } // render into a template - return $this->render('@ChillMain/Password/password.html.twig', array( - 'form' => $form->createView() - )); - - } - - /** - * @param User $user - * @return \Symfony\Component\Form\Form - */ - private function passwordForm(User $user) - { - return $this - ->createForm( - UserPasswordType::class, - [], - [ 'user' => $user ] - ) - ->add('submit', SubmitType::class, array('label' => 'Change password')) - ; - } - - /** - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - */ - public function recoverAction(Request $request) - { - if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) { - return (new Response($this->translator->trans("You are not allowed " - . "to try to recover password, due to mitigating possible " - . "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN)); - } - - $query = $request->query; - $username = $query->get(TokenManager::USERNAME_CANONICAL); - $hash = $query->getAlnum(TokenManager::HASH); - $token = $query->getAlnum(TokenManager::TOKEN); - $timestamp = $query->getInt(TokenManager::TIMESTAMP); - $user = $this->getDoctrine()->getRepository(User::class) - ->findOneByUsernameCanonical($username); - - if (NULL === $user) { - $this->eventDispatcher->dispatch(PasswordRecoverEvent::INVALID_TOKEN, - new PasswordRecoverEvent($token, null, $request->getClientIp())); - - throw $this->createNotFoundException(sprintf('User %s not found', $username)); - } - - if (TRUE !== $this->tokenManager->verify($hash, $token, $user, $timestamp)) { - $this->eventDispatcher->dispatch(PasswordRecoverEvent::INVALID_TOKEN, - new PasswordRecoverEvent($token, $user, $request->getClientIp())); - - return new Response("Invalid token", Response::HTTP_FORBIDDEN); - } - - $form = $this->passwordForm($user); - $form->remove('actual_password'); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - $password = $form->get('new_password')->getData(); - $user->setPassword($this->passwordEncoder->encodePassword($user, $password)); - // logging for prod - $this - ->chillLogger - ->notice( - 'setting new password for user', - array( - 'user' => $user->getUsername() - ) - ); - - $this->getDoctrine()->getManager()->flush(); - - return $this->redirectToRoute('password_request_recover_changed'); - } - - return $this->render('@ChillMain/Password/recover_password_form.html.twig', [ - 'form' => $form->createView() - ]); - - } - - /** - * @return Response - */ - public function changeConfirmedAction() - { - return $this->render('@ChillMain/Password/recover_password_changed.html.twig'); - } - - /** - * @param Request $request - * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response - * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException - */ - public function requestRecoverAction(Request $request) - { - if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN)) { - return (new Response($this->translator->trans("You are not allowed " - . "to try to recover password, due to mitigating possible " - . "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN)); - } - - $form = $this->requestRecoverForm(); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { - /* @var $qb \Doctrine\ORM\QueryBuilder */ - $qb = $this->getDoctrine()->getManager() - ->createQueryBuilder(); - $qb->select('u') - ->from(User::class, 'u') - ->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))')) - ->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))' )) - ->setParameter('pattern', $form->get('username_or_email')->getData()) - ; - - $user = $qb->getQuery()->getSingleResult(); - - if (empty($user->getEmail())) { - $this->addFlash('error', $this->translator->trans('This account does not have an email address. ' - . 'Please ask your administrator to renew your password.')); - } else { - if (FALSE === $this->isGranted(PasswordRecoverVoter::ASK_TOKEN, $user)) { - return (new Response($this->translator->trans("You are not allowed " - . "to try to recover password, due to mitigating possible " - . "attack. Try to contact your system administrator"), Response::HTTP_FORBIDDEN)); - } - - $this->recoverPasswordHelper->sendRecoverEmail($user, - (new \DateTimeImmutable('now'))->add(new \DateInterval('PT30M'))); - - // logging for prod - $this - ->chillLogger - ->notice( - 'Sending an email for password recovering', - array( - 'user' => $user->getUsername() - ) - ); - - $this->eventDispatcher->dispatch( - PasswordRecoverEvent::ASK_TOKEN_SUCCESS, - new PasswordRecoverEvent(null, $user, $request->getClientIp()) - ); - - return $this->redirectToRoute('password_request_recover_confirm'); - } - } elseif ($form->isSubmitted() && FALSE === $form->isValid()) { - $this->eventDispatcher->dispatch( - PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM, - new PasswordRecoverEvent(null, null, $request->getClientIp()) - ); - } - - return $this->render('@ChillMain/Password/request_recover_password.html.twig', [ - 'form' => $form->createView() + return $this->render('@ChillMain/Password/password.html.twig', [ + 'form' => $form->createView(), ]); } - - /** - * @return Response - */ - public function requestRecoverConfirmAction() - { - return $this->render('@ChillMain/Password/request_recover_password_confirm.html.twig'); - } - + /** * @return \Symfony\Component\Form\FormInterface */ @@ -310,27 +293,40 @@ class PasswordController extends AbstractController 'label' => 'Username or email', 'constraints' => [ new Callback([ - 'callback' => function($pattern, ExecutionContextInterface $context, $payload) { + 'callback' => function ($pattern, ExecutionContextInterface $context, $payload) { $qb = $this->getDoctrine()->getManager() - ->createQueryBuilder(); + ->createQueryBuilder(); $qb->select('COUNT(u)') ->from(User::class, 'u') ->where($qb->expr()->eq('u.usernameCanonical', 'UNACCENT(LOWER(:pattern))')) - ->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))' )) - ->setParameter('pattern', $pattern) - ; + ->orWhere($qb->expr()->eq('u.emailCanonical', 'UNACCENT(LOWER(:pattern))')) + ->setParameter('pattern', $pattern); if ((int) $qb->getQuery()->getSingleScalarResult() !== 1) { $context->addViolation('This username or email does not exists'); } - } - ]) - ] + }, + ]), + ], ]) ->add('submit', SubmitType::class, [ - 'label' => 'Request recover' + 'label' => 'Request recover', ]); - + return $builder->getForm(); } + + /** + * @return \Symfony\Component\Form\Form + */ + private function passwordForm(User $user) + { + return $this + ->createForm( + UserPasswordType::class, + [], + ['user' => $user] + ) + ->add('submit', SubmitType::class, ['label' => 'Change password']); + } } diff --git a/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php b/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php index 0a46c4496..bc6e68e83 100644 --- a/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php +++ b/src/Bundle/ChillMainBundle/Controller/PermissionsGroupController.php @@ -1,62 +1,62 @@ translatableStringHelper = $translatableStringHelper; $this->roleProvider = $roleProvider; $this->roleHierarchy = $roleHierarchy; $this->translator = $translator; $this->validator = $validator; } - + /** - * Lists all PermissionsGroup entities. + * @param int $id * + * @throws type + * + * @return Respon */ - public function indexAction() + public function addLinkRoleScopeAction(Request $request, $id) { $em = $this->getDoctrine()->getManager(); - $entities = $em->getRepository('ChillMainBundle:PermissionsGroup')->findAll(); + $permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id); - return $this->render('@ChillMain/PermissionsGroup/index.html.twig', array( - 'entities' => $entities, - )); + if (!$permissionsGroup) { + throw $this->createNotFoundException('Unable to find PermissionsGroup entity.'); + } + + $form = $this->createAddRoleScopeForm($permissionsGroup); + $form->handleRequest($request); + + if ($form->isValid()) { + $roleScope = $this->getPersistentRoleScopeBy( + $form['composed_role_scope']->getData()->getRole(), + $form['composed_role_scope']->getData()->getScope() + ); + + $permissionsGroup->addRoleScope($roleScope); + $violations = $this->validator->validate($permissionsGroup); + + if ($violations->count() === 0) { + $em->flush(); + + $this->addFlash( + 'notice', + $this->translator->trans('The permissions have been added') + ); + + return $this->redirect($this->generateUrl( + 'admin_permissionsgroup_edit', + ['id' => $id] + )); + } + + foreach ($violations as $error) { + $this->addFlash('error', $error->getMessage()); + } + } else { + foreach ($form->getErrors() as $error) { + $this->addFlash('error', $error->getMessage()); + } + } + + $editForm = $this->createEditForm($permissionsGroup); + + $deleteRoleScopesForm = []; + + foreach ($permissionsGroup->getRoleScopes() as $roleScope) { + $deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm( + $permissionsGroup, + $roleScope + ); + } + + $addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup); + + // sort role scope by title + + $roleProvider = $this->roleProvider; + $roleScopesSorted = []; + + foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { + /* @var $roleScope RoleScope */ + $title = $roleProvider->getRoleTitle($roleScope->getRole()); + $roleScopesSorted[$title][] = $roleScope; + } + ksort($roleScopesSorted); + + return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [ + 'entity' => $permissionsGroup, + 'edit_form' => $editForm->createView(), + 'role_scopes_sorted' => $roleScopesSorted, + 'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()), + 'delete_role_scopes_form' => array_map(function ($form) { + return $form->createView(); + }, $deleteRoleScopesForm), + 'add_role_scopes_form' => $addRoleScopesForm->createView(), + ]); } /** * Creates a new PermissionsGroup entity. - * */ public function createAction(Request $request) { @@ -103,284 +175,24 @@ class PermissionsGroupController extends AbstractController $em->persist($permissionsGroup); $em->flush(); - return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', - array('id' => $permissionsGroup->getId()))); + return $this->redirect($this->generateUrl( + 'admin_permissionsgroup_edit', + ['id' => $permissionsGroup->getId()] + )); } - return $this->render('@ChillMain/PermissionsGroup/new.html.twig', array( + return $this->render('@ChillMain/PermissionsGroup/new.html.twig', [ 'entity' => $permissionsGroup, - 'form' => $form->createView(), - )); + 'form' => $form->createView(), + ]); } /** - * Creates a form to create a PermissionsGroup entity. - * - * @param PermissionsGroup $permissionsGroup The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(PermissionsGroup $permissionsGroup) - { - $form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, array( - 'action' => $this->generateUrl('admin_permissionsgroup_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new PermissionsGroup entity. - * - */ - public function newAction() - { - $permissionsGroup = new PermissionsGroup(); - $form = $this->createCreateForm($permissionsGroup); - - return $this->render('@ChillMain/PermissionsGroup/new.html.twig', array( - 'entity' => $permissionsGroup, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a PermissionsGroup entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id); - - if (!$permissionsGroup) { - throw $this->createNotFoundException('Unable to find PermissionsGroup entity.'); - } - - $translatableStringHelper = $this->translatableStringHelper; - $roleScopes = $permissionsGroup->getRoleScopes()->toArray(); - - // sort $roleScopes by name - usort($roleScopes, - function(RoleScope $a, RoleScope $b) use ($translatableStringHelper) { - if ($a->getScope() === NULL) { - return 1; - } - if ($b->getScope() === NULL) { - return +1; - } - - return strcmp( - $translatableStringHelper->localize($a->getScope()->getName()), - $translatableStringHelper->localize($b->getScope()->getName()) - ); - }); - - // sort role scope by title - $roleProvider = $this->roleProvider; - $roleScopesSorted = array(); - foreach($roleScopes as $roleScope) { - - /* @var $roleScope RoleScope */ - $title = $roleProvider->getRoleTitle($roleScope->getRole()); - $roleScopesSorted[$title][] = $roleScope; - } - ksort($roleScopesSorted); - - return $this->render('@ChillMain/PermissionsGroup/show.html.twig', array( - 'entity' => $permissionsGroup, - 'role_scopes_sorted' => $roleScopesSorted, - 'expanded_roles' => $this->getExpandedRoles($roleScopes) - )); - } - - /** - * expand roleScopes to be easily shown in template - * - * @param array $roleScopes - * @return array - */ - private function getExpandedRoles(array $roleScopes) - { - $expandedRoles = array(); - foreach ($roleScopes as $roleScope) { - if (!array_key_exists($roleScope->getRole(), $expandedRoles)) { - $expandedRoles[$roleScope->getRole()] = - array_map( - function(Role $role) { - return $role->getRole(); - }, - $this->roleHierarchy - ->getReachableRoles( - array(new Role($roleScope->getRole())) - ) - ); - } - } - return $expandedRoles; - } - - /** - * Displays a form to edit an existing PermissionsGroup entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id); - - if (!$permissionsGroup) { - throw $this->createNotFoundException('Unable to find PermissionsGroup entity.'); - } - - // create all the forms - $editForm = $this->createEditForm($permissionsGroup); - - $deleteRoleScopesForm = array(); - foreach ($permissionsGroup->getRoleScopes() as $roleScope) { - $deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm( - $permissionsGroup, $roleScope); - } - - $addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup); - - // sort role scope by title - $roleProvider = $this->roleProvider; - $roleScopesSorted = array(); - foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { - /* @var $roleScope RoleScope */ - $title = $roleProvider->getRoleTitle($roleScope->getRole()); - $roleScopesSorted[$title][] = $roleScope; - } - ksort($roleScopesSorted); - - return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array( - 'entity' => $permissionsGroup, - 'role_scopes_sorted' => $roleScopesSorted, - 'edit_form' => $editForm->createView(), - 'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()), - 'delete_role_scopes_form' => array_map( function($form) { - - return $form->createView(); - }, $deleteRoleScopesForm), - 'add_role_scopes_form' => $addRoleScopesForm->createView() - )); - } - - /** - * Creates a form to edit a PermissionsGroup entity. - * - * @param PermissionsGroup $permissionsGroup The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(PermissionsGroup $permissionsGroup) - { - $form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, array( - 'action' => $this->generateUrl('admin_permissionsgroup_update', array('id' => $permissionsGroup->getId())), - 'method' => 'PUT', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Update')); - - return $form; - } - - /** - * Edits an existing PermissionsGroup entity. - * - */ - public function updateAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); - - $permissionsGroup = $em - ->getRepository('ChillMainBundle:PermissionsGroup') - ->find($id); - - if (!$permissionsGroup) { - throw $this->createNotFoundException('Unable to find Permissions' - . 'Group entity.'); - } - - $editForm = $this->createEditForm($permissionsGroup); - $editForm->handleRequest($request); - - if ($editForm->isValid()) { - - $em->flush(); - - return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', array('id' => $id))); - } - - $deleteRoleScopesForm = array(); - foreach ($permissionsGroup->getRoleScopes() as $roleScope) { - $deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm( - $permissionsGroup, $roleScope); - } - - $addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup); - - // sort role scope by title - $roleProvider = $this->roleProvider; - $roleScopesSorted = array(); - foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { - /* @var $roleScope RoleScope */ - $title = $roleProvider->getRoleTitle($roleScope->getRole()); - $roleScopesSorted[$title][] = $roleScope; - } - ksort($roleScopesSorted); - - return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array( - 'entity' => $permissionsGroup, - 'role_scopes_sorted' => $roleScopesSorted, - 'edit_form' => $editForm->createView(), - 'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()), - 'delete_role_scopes_form' => array_map( function($form) { - - return $form->createView(); - }, $deleteRoleScopesForm), - 'add_role_scopes_form' => $addRoleScopesForm->createView() - )); - } - - /** - * get a role scope by his parameters. The role scope is persisted if it - * doesn't exists in database. - * - * @param Scope $scope - * @param string $role - * @return RoleScope - */ - protected function getPersistentRoleScopeBy($role, Scope $scope = null) - { - $em = $this->getDoctrine()->getManager(); - - $roleScope = $em->getRepository('ChillMainBundle:RoleScope') - ->findOneBy(array('role' => $role, 'scope' => $scope)); - - if ($roleScope === NULL) { - $roleScope = (new RoleScope()) - ->setRole($role) - ->setScope($scope) - ; - - $em->persist($roleScope); - } - - return $roleScope; - } - - /** - * remove an association between permissionsGroup and roleScope + * remove an association between permissionsGroup and roleScope. * * @param int $pgid permissionsGroup id * @param int $rsid roleScope id + * * @return redirection to edit form */ public function deleteLinkRoleScopeAction($pgid, $rsid) @@ -400,48 +212,56 @@ class PermissionsGroupController extends AbstractController try { $permissionsGroup->removeRoleScope($roleScope); - } catch (\RuntimeException $ex) { - $this->addFlash('notice', + } catch (RuntimeException $ex) { + $this->addFlash( + 'notice', $this->translator->trans("The role '%role%' and circle " - . "'%scope%' is not associated with this permission group", array( + . "'%scope%' is not associated with this permission group", [ '%role%' => $this->translator->trans($roleScope->getRole()), '%scope%' => $this->translatableStringHelper - ->localize($roleScope->getScope()->getName()) - ))); + ->localize($roleScope->getScope()->getName()), + ]) + ); - return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', - array('id' => $pgid))); + return $this->redirect($this->generateUrl( + 'admin_permissionsgroup_edit', + ['id' => $pgid] + )); } $em->flush(); - if ($roleScope->getScope() !== NULL ) { - $this->addFlash('notice', + if ($roleScope->getScope() !== null) { + $this->addFlash( + 'notice', $this->translator->trans("The role '%role%' on circle " - . "'%scope%' has been removed", array( + . "'%scope%' has been removed", [ '%role%' => $this->translator->trans($roleScope->getRole()), '%scope%' => $this->translatableStringHelper - ->localize($roleScope->getScope()->getName()) - ))); + ->localize($roleScope->getScope()->getName()), + ]) + ); } else { - $this->addFlash('notice', - $this->translator->trans("The role '%role%' has been removed", array( - '%role%' => $this->translator->trans($roleScope->getRole()) - ))); + $this->addFlash( + 'notice', + $this->translator->trans("The role '%role%' has been removed", [ + '%role%' => $this->translator->trans($roleScope->getRole()), + ]) + ); } - return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', - array('id' => $pgid))); + return $this->redirect($this->generateUrl( + 'admin_permissionsgroup_edit', + ['id' => $pgid] + )); } /** + * Displays a form to edit an existing PermissionsGroup entity. * - * @param Request $request - * @param int $id - * @return Respon - * @throws type + * @param mixed $id */ - public function addLinkRoleScopeAction(Request $request, $id) + public function editAction($id) { $em = $this->getDoctrine()->getManager(); @@ -451,71 +271,249 @@ class PermissionsGroupController extends AbstractController throw $this->createNotFoundException('Unable to find PermissionsGroup entity.'); } - $form = $this->createAddRoleScopeForm($permissionsGroup); - $form->handleRequest($request); - - if ($form->isValid()) { - $roleScope = $this->getPersistentRoleScopeBy( - $form['composed_role_scope']->getData()->getRole(), - $form['composed_role_scope']->getData()->getScope() - ); - - $permissionsGroup->addRoleScope($roleScope); - $violations = $this->validator->validate($permissionsGroup); - - if ($violations->count() === 0) { - $em->flush(); - - $this->addFlash('notice', - $this->translator->trans("The permissions have been added")); - - return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', - array('id' => $id))); - } else { - foreach($violations as $error) { - $this->addFlash('error', $error->getMessage()); - } - } - - } else { - foreach ($form->getErrors() as $error) { - $this->addFlash('error', $error->getMessage()); - } - } - + // create all the forms $editForm = $this->createEditForm($permissionsGroup); - $deleteRoleScopesForm = array(); + $deleteRoleScopesForm = []; + foreach ($permissionsGroup->getRoleScopes() as $roleScope) { $deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm( - $permissionsGroup, $roleScope); + $permissionsGroup, + $roleScope + ); } $addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup); // sort role scope by title - $roleProvider = $this->roleProvider; - $roleScopesSorted = array(); - foreach($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { + $roleScopesSorted = []; + + foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { /* @var $roleScope RoleScope */ $title = $roleProvider->getRoleTitle($roleScope->getRole()); $roleScopesSorted[$title][] = $roleScope; } ksort($roleScopesSorted); - return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', array( - 'entity' => $permissionsGroup, - 'edit_form' => $editForm->createView(), + return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [ + 'entity' => $permissionsGroup, 'role_scopes_sorted' => $roleScopesSorted, + 'edit_form' => $editForm->createView(), 'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()), - 'delete_role_scopes_form' => array_map( function($form) { - + 'delete_role_scopes_form' => array_map(function ($form) { return $form->createView(); }, $deleteRoleScopesForm), - 'add_role_scopes_form' => $addRoleScopesForm->createView() - )); + 'add_role_scopes_form' => $addRoleScopesForm->createView(), + ]); + } + /** + * Lists all PermissionsGroup entities. + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + + $entities = $em->getRepository('ChillMainBundle:PermissionsGroup')->findAll(); + + return $this->render('@ChillMain/PermissionsGroup/index.html.twig', [ + 'entities' => $entities, + ]); + } + + /** + * Displays a form to create a new PermissionsGroup entity. + */ + public function newAction() + { + $permissionsGroup = new PermissionsGroup(); + $form = $this->createCreateForm($permissionsGroup); + + return $this->render('@ChillMain/PermissionsGroup/new.html.twig', [ + 'entity' => $permissionsGroup, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a PermissionsGroup entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id); + + if (!$permissionsGroup) { + throw $this->createNotFoundException('Unable to find PermissionsGroup entity.'); + } + + $translatableStringHelper = $this->translatableStringHelper; + $roleScopes = $permissionsGroup->getRoleScopes()->toArray(); + + // sort $roleScopes by name + usort( + $roleScopes, + function (RoleScope $a, RoleScope $b) use ($translatableStringHelper) { + if ($a->getScope() === null) { + return 1; + } + + if ($b->getScope() === null) { + return +1; + } + + return strcmp( + $translatableStringHelper->localize($a->getScope()->getName()), + $translatableStringHelper->localize($b->getScope()->getName()) + ); + } + ); + + // sort role scope by title + $roleProvider = $this->roleProvider; + $roleScopesSorted = []; + + foreach ($roleScopes as $roleScope) { + /* @var $roleScope RoleScope */ + $title = $roleProvider->getRoleTitle($roleScope->getRole()); + $roleScopesSorted[$title][] = $roleScope; + } + ksort($roleScopesSorted); + + return $this->render('@ChillMain/PermissionsGroup/show.html.twig', [ + 'entity' => $permissionsGroup, + 'role_scopes_sorted' => $roleScopesSorted, + 'expanded_roles' => $this->getExpandedRoles($roleScopes), + ]); + } + + /** + * Edits an existing PermissionsGroup entity. + * + * @param mixed $id + */ + public function updateAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + + $permissionsGroup = $em + ->getRepository('ChillMainBundle:PermissionsGroup') + ->find($id); + + if (!$permissionsGroup) { + throw $this->createNotFoundException('Unable to find Permissions' + . 'Group entity.'); + } + + $editForm = $this->createEditForm($permissionsGroup); + $editForm->handleRequest($request); + + if ($editForm->isValid()) { + $em->flush(); + + return $this->redirect($this->generateUrl('admin_permissionsgroup_edit', ['id' => $id])); + } + + $deleteRoleScopesForm = []; + + foreach ($permissionsGroup->getRoleScopes() as $roleScope) { + $deleteRoleScopesForm[$roleScope->getId()] = $this->createDeleteRoleScopeForm( + $permissionsGroup, + $roleScope + ); + } + + $addRoleScopesForm = $this->createAddRoleScopeForm($permissionsGroup); + + // sort role scope by title + $roleProvider = $this->roleProvider; + $roleScopesSorted = []; + + foreach ($permissionsGroup->getRoleScopes()->toArray() as $roleScope) { + /* @var $roleScope RoleScope */ + $title = $roleProvider->getRoleTitle($roleScope->getRole()); + $roleScopesSorted[$title][] = $roleScope; + } + ksort($roleScopesSorted); + + return $this->render('@ChillMain/PermissionsGroup/edit.html.twig', [ + 'entity' => $permissionsGroup, + 'role_scopes_sorted' => $roleScopesSorted, + 'edit_form' => $editForm->createView(), + 'expanded_roles' => $this->getExpandedRoles($permissionsGroup->getRoleScopes()->toArray()), + 'delete_role_scopes_form' => array_map(function ($form) { + return $form->createView(); + }, $deleteRoleScopesForm), + 'add_role_scopes_form' => $addRoleScopesForm->createView(), + ]); + } + + /** + * get a role scope by his parameters. The role scope is persisted if it + * doesn't exists in database. + * + * @param Scope $scope + * @param string $role + * + * @return RoleScope + */ + protected function getPersistentRoleScopeBy($role, ?Scope $scope = null) + { + $em = $this->getDoctrine()->getManager(); + + $roleScope = $em->getRepository('ChillMainBundle:RoleScope') + ->findOneBy(['role' => $role, 'scope' => $scope]); + + if (null === $roleScope) { + $roleScope = (new RoleScope()) + ->setRole($role) + ->setScope($scope); + + $em->persist($roleScope); + } + + return $roleScope; + } + + /** + * creates a form to add a role scope to permissionsgroup. + * + * @return \Symfony\Component\Form\Form The form + */ + private function createAddRoleScopeForm(PermissionsGroup $permissionsGroup) + { + return $this->createFormBuilder() + ->setAction($this->generateUrl( + 'admin_permissionsgroup_add_role_scope', + ['id' => $permissionsGroup->getId()] + )) + ->setMethod('PUT') + ->add('composed_role_scope', ComposedRoleScopeType::class) + ->add('submit', SubmitType::class, ['label' => 'Add permission']) + ->getForm(); + } + + /** + * Creates a form to create a PermissionsGroup entity. + * + * @param PermissionsGroup $permissionsGroup The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(PermissionsGroup $permissionsGroup) + { + $form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, [ + 'action' => $this->generateUrl('admin_permissionsgroup_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; } /** @@ -525,35 +523,62 @@ class PermissionsGroupController extends AbstractController * * @return \Symfony\Component\Form\Form The form */ - private function createDeleteRoleScopeForm(PermissionsGroup $permissionsGroup, - RoleScope $roleScope) - { + private function createDeleteRoleScopeForm( + PermissionsGroup $permissionsGroup, + RoleScope $roleScope + ) { return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_permissionsgroup_delete_role_scope', - array('pgid' => $permissionsGroup->getId(), 'rsid' => $roleScope->getId()))) + ->setAction($this->generateUrl( + 'admin_permissionsgroup_delete_role_scope', + ['pgid' => $permissionsGroup->getId(), 'rsid' => $roleScope->getId()] + )) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); } /** - * creates a form to add a role scope to permissionsgroup + * Creates a form to edit a PermissionsGroup entity. + * + * @param PermissionsGroup $permissionsGroup The entity * - * @param PermissionsGroup $permissionsGroup * @return \Symfony\Component\Form\Form The form */ - private function createAddRoleScopeForm(PermissionsGroup $permissionsGroup) + private function createEditForm(PermissionsGroup $permissionsGroup) { - return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_permissionsgroup_add_role_scope', - array('id' => $permissionsGroup->getId()))) - ->setMethod('PUT') - ->add('composed_role_scope', ComposedRoleScopeType::class) - ->add('submit', SubmitType::class, array('label' => 'Add permission')) - ->getForm() - ; + $form = $this->createForm(PermissionsGroupType::class, $permissionsGroup, [ + 'action' => $this->generateUrl('admin_permissionsgroup_update', ['id' => $permissionsGroup->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } + /** + * expand roleScopes to be easily shown in template. + * + * @return array + */ + private function getExpandedRoles(array $roleScopes) + { + $expandedRoles = []; + foreach ($roleScopes as $roleScope) { + if (!array_key_exists($roleScope->getRole(), $expandedRoles)) { + $expandedRoles[$roleScope->getRole()] = + array_map( + function (Role $role) { + return $role->getRole(); + }, + $this + ->roleHierarchy + ->getReachableRoles([new Role($roleScope->getRole())]) + ); + } + } + + return $expandedRoles; + } } diff --git a/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php b/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php index fb88e0763..542dc25c3 100644 --- a/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php +++ b/src/Bundle/ChillMainBundle/Controller/PostalCodeController.php @@ -1,90 +1,77 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Controller; - -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; -use Chill\MainBundle\Entity\PostalCode; -use Symfony\Component\HttpFoundation\JsonResponse; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\Query; /** - * Class PostalCodeController + * Chill is a software for social workers * - * @package Chill\MainBundle\Controller - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Controller; + +use Chill\MainBundle\Entity\PostalCode; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\Query; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Routing\Annotation\Route; + +use function array_map; + +/** + * Class PostalCodeController. */ class PostalCodeController extends AbstractController { /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; - + public function __construct(TranslatableStringHelper $translatableStringHelper) { $this->translatableStringHelper = $translatableStringHelper; } - /** - * * @Route( - * "{_locale}/postalcode/search" + * "{_locale}/postalcode/search" * ) - * @param Request $request + * * @return JsonResponse */ public function searchAction(Request $request) { $pattern = $request->query->getAlnum('q', ''); - + if (empty($pattern)) { - return new JsonResponse(["results" => [], "pagination" => [ "more" => false]]); + return new JsonResponse(['results' => [], 'pagination' => ['more' => false]]); } - + $query = $this->getDoctrine()->getManager() - ->createQuery(sprintf( - "SELECT p.id AS id, p.name AS name, p.code AS code, " - . "country.name AS country_name, " - . "country.countryCode AS country_code " - . "FROM %s p " - . "JOIN p.country country " - . "WHERE LOWER(p.name) LIKE LOWER(:pattern) OR LOWER(p.code) LIKE LOWER(:pattern) " - . "ORDER BY code" - , PostalCode::class) + ->createQuery( + sprintf( + 'SELECT p.id AS id, p.name AS name, p.code AS code, ' + . 'country.name AS country_name, ' + . 'country.countryCode AS country_code ' + . 'FROM %s p ' + . 'JOIN p.country country ' + . 'WHERE LOWER(p.name) LIKE LOWER(:pattern) OR LOWER(p.code) LIKE LOWER(:pattern) ' + . 'ORDER BY code', + PostalCode::class ) - ->setParameter('pattern', '%'.$pattern.'%') - ->setMaxResults(30) - ; - - $results = \array_map(function($row) { + ) + ->setParameter('pattern', '%' . $pattern . '%') + ->setMaxResults(30); + + $results = array_map(function ($row) { $row['country_name'] = $this->translatableStringHelper->localize($row['country_name']); - $row['text'] = $row['code']." ".$row["name"]." (".$row['country_name'].")"; - + $row['text'] = $row['code'] . ' ' . $row['name'] . ' (' . $row['country_name'] . ')'; + return $row; }, $query->getResult(Query::HYDRATE_ARRAY)); - - return new JsonResponse([ 'results' => $results, "pagination" => [ "more" => false ] ]); + + return new JsonResponse(['results' => $results, 'pagination' => ['more' => false]]); } } diff --git a/src/Bundle/ChillMainBundle/Controller/ScopeController.php b/src/Bundle/ChillMainBundle/Controller/ScopeController.php index 33e37ad94..8fae5d730 100644 --- a/src/Bundle/ChillMainBundle/Controller/ScopeController.php +++ b/src/Bundle/ChillMainBundle/Controller/ScopeController.php @@ -1,38 +1,27 @@ getDoctrine()->getManager(); - - $entities = $em->getRepository('ChillMainBundle:Scope')->findAll(); - - return $this->render('@ChillMain/Scope/index.html.twig', array( - 'entities' => $entities, - )); - } /** * Creates a new Scope entity. - * */ public function createAction(Request $request) { @@ -45,71 +34,19 @@ class ScopeController extends AbstractController $em->persist($scope); $em->flush(); - return $this->redirect($this->generateUrl('admin_scope_show', array('id' => $scope->getId()))); + return $this->redirect($this->generateUrl('admin_scope_show', ['id' => $scope->getId()])); } - return $this->render('@ChillMain/Scope/new.html.twig', array( + return $this->render('@ChillMain/Scope/new.html.twig', [ 'entity' => $scope, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a Scope entity. - * - * @param Scope $scope The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Scope $scope) - { - $form = $this->createForm(ScopeType::class, $scope, array( - 'action' => $this->generateUrl('admin_scope_create'), - 'method' => 'POST', - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new Scope entity. - * - */ - public function newAction() - { - $scope = new Scope(); - $form = $this->createCreateForm($scope); - - return $this->render('@ChillMain/Scope/new.html.twig', array( - 'entity' => $scope, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a Scope entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $scope = $em->getRepository('ChillMainBundle:Scope')->find($id); - - if (!$scope) { - throw $this->createNotFoundException('Unable to find Scope entity.'); - } - - return $this->render('@ChillMain/Scope/show.html.twig', array( - 'entity' => $scope - )); + 'form' => $form->createView(), + ]); } /** * Displays a form to edit an existing Scope entity. * + * @param mixed $id */ public function editAction($id) { @@ -123,33 +60,64 @@ class ScopeController extends AbstractController $editForm = $this->createEditForm($scope); - return $this->render('@ChillMain/Scope/edit.html.twig', array( - 'entity' => $scope, - 'edit_form' => $editForm->createView(), - )); + return $this->render('@ChillMain/Scope/edit.html.twig', [ + 'entity' => $scope, + 'edit_form' => $editForm->createView(), + ]); } /** - * Creates a form to edit a Scope entity. - * - * @param Scope $scope The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(Scope $scope) + * Lists all Scope entities. + */ + public function indexAction() { - $form = $this->createForm(ScopeType::class, $scope, array( - 'action' => $this->generateUrl('admin_scope_update', array('id' => $scope->getId())), - 'method' => 'PUT', - )); + $em = $this->getDoctrine()->getManager(); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + $entities = $em->getRepository('ChillMainBundle:Scope')->findAll(); - return $form; + return $this->render('@ChillMain/Scope/index.html.twig', [ + 'entities' => $entities, + ]); } + + /** + * Displays a form to create a new Scope entity. + */ + public function newAction() + { + $scope = new Scope(); + $form = $this->createCreateForm($scope); + + return $this->render('@ChillMain/Scope/new.html.twig', [ + 'entity' => $scope, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a Scope entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $scope = $em->getRepository('ChillMainBundle:Scope')->find($id); + + if (!$scope) { + throw $this->createNotFoundException('Unable to find Scope entity.'); + } + + return $this->render('@ChillMain/Scope/show.html.twig', [ + 'entity' => $scope, + ]); + } + /** * Edits an existing Scope entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -167,12 +135,50 @@ class ScopeController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('admin_scope_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('admin_scope_edit', ['id' => $id])); } - return $this->render('@ChillMain/Scope/edit.html.twig', array( - 'entity' => $scope, - 'edit_form' => $editForm->createView() - )); + return $this->render('@ChillMain/Scope/edit.html.twig', [ + 'entity' => $scope, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Creates a form to create a Scope entity. + * + * @param Scope $scope The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(Scope $scope) + { + $form = $this->createForm(ScopeType::class, $scope, [ + 'action' => $this->generateUrl('admin_scope_create'), + 'method' => 'POST', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to edit a Scope entity. + * + * @param Scope $scope The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Scope $scope) + { + $form = $this->createForm(ScopeType::class, $scope, [ + 'action' => $this->generateUrl('admin_scope_update', ['id' => $scope->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; } } diff --git a/src/Bundle/ChillMainBundle/Controller/SearchController.php b/src/Bundle/ChillMainBundle/Controller/SearchController.php index a44af8e7b..e8217d16d 100644 --- a/src/Bundle/ChillMainBundle/Controller/SearchController.php +++ b/src/Bundle/ChillMainBundle/Controller/SearchController.php @@ -1,67 +1,53 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Controller; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\HttpFoundation\Request; -use Chill\MainBundle\Search\UnknowSearchDomainException; -use Chill\MainBundle\Search\UnknowSearchNameException; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Search\ParsingException; use Chill\MainBundle\Search\SearchInterface; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Form\Extension\Core\Type\FormType; -use Symfony\Component\HttpFoundation\JsonResponse; use Chill\MainBundle\Search\SearchProvider; +use Chill\MainBundle\Search\UnknowSearchDomainException; +use Chill\MainBundle\Search\UnknowSearchNameException; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\Translation\TranslatorInterface; -use Chill\MainBundle\Pagination\PaginatorFactory; + +use function count; +use function key; +use function reset; /** - * Class SearchController - * - * @package Chill\MainBundle\Controller + * Class SearchController. */ class SearchController extends AbstractController { /** - * - * @var SearchProvider - */ - protected $searchProvider; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var PaginatorFactory */ protected $paginatorFactory; - - function __construct( - SearchProvider $searchProvider, + + /** + * @var SearchProvider + */ + protected $searchProvider; + + /** + * @var TranslatorInterface + */ + protected $translator; + + public function __construct( + SearchProvider $searchProvider, TranslatorInterface $translator, PaginatorFactory $paginatorFactory ) { @@ -70,107 +56,6 @@ class SearchController extends AbstractController $this->paginatorFactory = $paginatorFactory; } - - public function searchAction(Request $request, $_format) - { - $pattern = $request->query->get('q', ''); - - if ($pattern === ''){ - switch($_format) { - case 'html': - return $this->render('@ChillMain/Search/error.html.twig', - array( - 'message' => $this->translator->trans("Your search is empty. " - . "Please provide search terms."), - 'pattern' => $pattern - )); - case 'json': - return new JsonResponse([ - 'results' => [], - 'pagination' => [ 'more' => false ] - ]); - } - } - - $name = $request->query->get('name', NULL); - - try { - if ($name === NULL) { - if ($_format === 'json') { - return new JsonResponse('Currently, we still do not aggregate results ' - . 'from different providers', JsonResponse::HTTP_BAD_REQUEST); - } - - // no specific search selected. Rendering result in "preview" mode - $results = $this->searchProvider - ->getSearchResults( - $pattern, - 0, - 5, - array(SearchInterface::SEARCH_PREVIEW_OPTION => true) - ); - } else { - // we want search on a specific search provider. Display full results. - $results = [$this->searchProvider - ->getResultByName( - $pattern, - $name, - $this->paginatorFactory->getCurrentPageFirstItemNumber(), - $this->paginatorFactory->getCurrentItemsPerPage(), - array( - SearchInterface::SEARCH_PREVIEW_OPTION => false, - SearchInterface::REQUEST_QUERY_PARAMETERS => $request - ->get(SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS, []) - ), - $_format - )]; - - if ($_format === 'json') { - return new JsonResponse(\reset($results)); - } - } - } catch (UnknowSearchDomainException $ex) { - return $this->render('@ChillMain/Search/error.html.twig', - array( - "message" => $this->translator->trans("The domain %domain% " - . "is unknow. Please check your search.", array('%domain%' => $ex->getDomain())), - 'pattern' => $pattern - )); - } catch (UnknowSearchNameException $ex) { - throw $this->createNotFoundException("The name ".$ex->getName()." is not found"); - } catch (ParsingException $ex) { - return $this->render('@ChillMain/Search/error.html.twig', - array( - "message" => $this->translator->trans('Invalid terms'). - ": ".$this->translator->trans($ex->getMessage()), - 'pattern' => $pattern - )); - } - - - return $this->render('@ChillMain/Search/list.html.twig', - array('results' => $results, 'pattern' => $pattern) - ); - } - - public function advancedSearchListAction(Request $request) - { - /* @var $variable Chill\MainBundle\Search\SearchProvider */ - $searchProvider = $this->searchProvider; - $advancedSearchProviders = $searchProvider - ->getHasAdvancedFormSearchServices(); - - if(\count($advancedSearchProviders) === 1) { - \reset($advancedSearchProviders); - - return $this->redirectToRoute('chill_main_advanced_search', [ - 'name' => \key($advancedSearchProviders) - ]); - } - - return $this->render('@ChillMain/Search/choose_list.html.twig'); - } - public function advancedSearchAction($name, Request $request) { try { @@ -178,63 +63,170 @@ class SearchController extends AbstractController $searchProvider = $this->searchProvider; /* @var $variable Chill\MainBundle\Search\HasAdvancedSearchFormInterface */ $search = $this->searchProvider - ->getHasAdvancedFormByName($name); - + ->getHasAdvancedFormByName($name); } catch (\Chill\MainBundle\Search\UnknowSearchNameException $e) { - throw $this->createNotFoundException("no advanced search for " - . "$name"); + throw $this->createNotFoundException('no advanced search for ' + . "{$name}"); } - + if ($request->query->has('q')) { $data = $search->convertTermsToFormData($searchProvider->parse( - $request->query->get('q'))); + $request->query->get('q') + )); } - + $form = $this->createAdvancedSearchForm($name, $data ?? []); - + if ($request->isMethod(Request::METHOD_POST)) { $form->handleRequest($request); - + if ($form->isValid()) { $pattern = $this->searchProvider ->getHasAdvancedFormByName($name) ->convertFormDataToQuery($form->getData()); return $this->redirectToRoute('chill_main_search', [ - 'q' => $pattern, 'name' => $name + 'q' => $pattern, 'name' => $name, ]); } - } - - return $this->render('@ChillMain/Search/advanced_search.html.twig', + } + + return $this->render( + '@ChillMain/Search/advanced_search.html.twig', [ 'form' => $form->createView(), 'name' => $name, - 'title' => $search->getAdvancedSearchTitle() - ]); + 'title' => $search->getAdvancedSearchTitle(), + ] + ); } - + + public function advancedSearchListAction(Request $request) + { + /* @var $variable Chill\MainBundle\Search\SearchProvider */ + $searchProvider = $this->searchProvider; + $advancedSearchProviders = $searchProvider + ->getHasAdvancedFormSearchServices(); + + if (count($advancedSearchProviders) === 1) { + reset($advancedSearchProviders); + + return $this->redirectToRoute('chill_main_advanced_search', [ + 'name' => key($advancedSearchProviders), + ]); + } + + return $this->render('@ChillMain/Search/choose_list.html.twig'); + } + + public function searchAction(Request $request, $_format) + { + $pattern = $request->query->get('q', ''); + + if ('' === $pattern) { + switch ($_format) { + case 'html': + return $this->render( + '@ChillMain/Search/error.html.twig', + [ + 'message' => $this->translator->trans('Your search is empty. ' + . 'Please provide search terms.'), + 'pattern' => $pattern, + ] + ); + + case 'json': + return new JsonResponse([ + 'results' => [], + 'pagination' => ['more' => false], + ]); + } + } + + $name = $request->query->get('name', null); + + try { + if (null === $name) { + if ('json' === $_format) { + return new JsonResponse('Currently, we still do not aggregate results ' + . 'from different providers', JsonResponse::HTTP_BAD_REQUEST); + } + + // no specific search selected. Rendering result in "preview" mode + $results = $this->searchProvider + ->getSearchResults( + $pattern, + 0, + 5, + [SearchInterface::SEARCH_PREVIEW_OPTION => true] + ); + } else { + // we want search on a specific search provider. Display full results. + $results = [$this->searchProvider + ->getResultByName( + $pattern, + $name, + $this->paginatorFactory->getCurrentPageFirstItemNumber(), + $this->paginatorFactory->getCurrentItemsPerPage(), + [ + SearchInterface::SEARCH_PREVIEW_OPTION => false, + SearchInterface::REQUEST_QUERY_PARAMETERS => $request + ->get(SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS, []), + ], + $_format + ), ]; + + if ('json' === $_format) { + return new JsonResponse(reset($results)); + } + } + } catch (UnknowSearchDomainException $ex) { + return $this->render( + '@ChillMain/Search/error.html.twig', + [ + 'message' => $this->translator->trans('The domain %domain% ' + . 'is unknow. Please check your search.', ['%domain%' => $ex->getDomain()]), + 'pattern' => $pattern, + ] + ); + } catch (UnknowSearchNameException $ex) { + throw $this->createNotFoundException('The name ' . $ex->getName() . ' is not found'); + } catch (ParsingException $ex) { + return $this->render( + '@ChillMain/Search/error.html.twig', + [ + 'message' => $this->translator->trans('Invalid terms') . + ': ' . $this->translator->trans($ex->getMessage()), + 'pattern' => $pattern, + ] + ); + } + + return $this->render( + '@ChillMain/Search/list.html.twig', + ['results' => $results, 'pattern' => $pattern] + ); + } + protected function createAdvancedSearchForm($name, array $data = []) { $builder = $this ->get('form.factory') ->createNamedBuilder( null, - FormType::class, - $data, - [ 'method' => Request::METHOD_POST ] + FormType::class, + $data, + ['method' => Request::METHOD_POST] ); $this->searchProvider ->getHasAdvancedFormByName($name) - ->buildForm($builder) - ; - + ->buildForm($builder); + $builder->add('submit', SubmitType::class, [ - 'label' => 'Search' + 'label' => 'Search', ]); - + return $builder->getForm(); } - } diff --git a/src/Bundle/ChillMainBundle/Controller/UIController.php b/src/Bundle/ChillMainBundle/Controller/UIController.php index 75992bf15..9424cfbad 100644 --- a/src/Bundle/ChillMainBundle/Controller/UIController.php +++ b/src/Bundle/ChillMainBundle/Controller/UIController.php @@ -1,30 +1,19 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Controller; - -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Chill\MainBundle\Templating\UI\CountNotificationUser; /** - * Class UIController + * Chill is a software for social workers * - * @package Chill\MainBundle\Controller - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Controller; + +use Chill\MainBundle\Templating\UI\CountNotificationUser; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; + +/** + * Class UIController. */ class UIController extends AbstractController { @@ -32,9 +21,9 @@ class UIController extends AbstractController CountNotificationUser $counter ) { $nb = $counter->getSumNotification($this->getUser()); - + return $this->render('@ChillMain/UI/notification_user_counter.html.twig', [ - 'nb' => $nb + 'nb' => $nb, ]); } } diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index 7de280d1d..63f91452f 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -1,252 +1,51 @@ logger = $logger; $this->validator = $validator; } - - /** - * Lists all User entities. - * - */ - public function indexAction() - { - $em = $this->getDoctrine()->getManager(); - - $entities = $em->createQuery('SELECT u FROM ChillMainBundle:User u ' - . 'ORDER BY u.username') - ->getResult(); - - return $this->render('@ChillMain/User/index.html.twig', array( - 'entities' => $entities, - )); - } - /** - * Creates a new User entity. - * - */ - public function createAction(Request $request) - { - $user = new User(); - $form = $this->createCreateForm($user); - $form->handleRequest($request); - - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - - $user->setPassword($this->get('security.password_encoder') - ->encodePassword($user, $form['plainPassword']->getData())); - - $em->persist($user); - $em->flush(); - - return $this->redirect($this->generateUrl('admin_user_show', array('id' => $user->getId()))); - } - - return $this->render('@ChillMain/User/new.html.twig', array( - 'entity' => $user, - 'form' => $form->createView(), - )); - } - - /** - * Creates a form to create a User entity. - * - * @param User $entity The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(User $entity) - { - $form = $this->createForm(UserType::class, $entity, array( - 'action' => $this->generateUrl('admin_user_create'), - 'method' => 'POST', - 'is_creation' => true - )); - - $form->add('submit', SubmitType::class, array('label' => 'Create')); - - return $form; - } - - /** - * Displays a form to create a new User entity. - * - */ - public function newAction() - { - $user = new User(); - $form = $this->createCreateForm($user); - - return $this->render('@ChillMain/User/new.html.twig', array( - 'entity' => $user, - 'form' => $form->createView(), - )); - } - - /** - * Finds and displays a User entity. - * - */ - public function showAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $user = $em->getRepository('ChillMainBundle:User')->find($id); - - if (!$user) { - throw $this->createNotFoundException('Unable to find User entity.'); - } - - return $this->render('@ChillMain/User/show.html.twig', array( - 'entity' => $user, - )); - } - - /** - * Displays a form to edit an existing User entity. - * - */ - public function editAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $user = $em->getRepository('ChillMainBundle:User')->find($id); - - if (!$user) { - throw $this->createNotFoundException('Unable to find User entity.'); - } - - $editForm = $this->createEditForm($user); - - return $this->render('@ChillMain/User/edit.html.twig', array( - 'entity' => $user, - 'edit_form' => $editForm->createView(), - 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(), - 'delete_groupcenter_form' => array_map( - function(\Symfony\Component\Form\Form $form) { - return $form->createView(); - - }, - iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true)) - )); - } - - /** - * Displays a form to edit the user password. - * - */ - public function editPasswordAction($id) - { - $em = $this->getDoctrine()->getManager(); - - $user = $em->getRepository('ChillMainBundle:User')->find($id); - - if (!$user) { - throw $this->createNotFoundException('Unable to find User entity.'); - } - - $editForm = $this->createEditPasswordForm($user); - - return $this->render('@ChillMain/User/edit_password.html.twig', array( - 'entity' => $user, - 'edit_form' => $editForm->createView() - )); - } - - /** - * - * - * @param User $user - * @return \Symfony\Component\Form\Form - */ - private function createEditPasswordForm(User $user) - { - return $this->createForm(UserPasswordType::class, null, array( - 'action' => - $this->generateUrl('admin_user_update_password', array('id' => $user->getId())), - 'method' => 'PUT', - 'user' => $user - )) - ->add('submit', SubmitType::class, array('label' => 'Change password')) - ->remove('actual_password') - ; - } - - public function deleteLinkGroupCenterAction($uid, $gcid) - { - $em = $this->getDoctrine()->getManager(); - - $user = $em->getRepository('ChillMainBundle:User')->find($uid); - - if (!$user) { - throw $this->createNotFoundException('Unable to find User entity.'); - } - - $groupCenter = $em->getRepository('ChillMainBundle:GroupCenter') - ->find($gcid); - - if (!$groupCenter) { - throw $this->createNotFoundException('Unable to find groupCenter entity'); - } - - try { - $user->removeGroupCenter($groupCenter); - } catch (\RuntimeException $ex) { - $this->addFlash('error', $this->get('translator')->trans($ex->getMessage())); - - return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $uid))); - } - - $em->flush(); - - $this->addFlash('success', $this->get('translator') - ->trans('The permissions where removed.')); - - return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $uid))); - - } public function addLinkGroupCenterAction(Request $request, $uid) { @@ -263,76 +62,207 @@ class UserController extends AbstractController if ($form->isValid()) { $groupCenter = $this->getPersistedGroupCenter( - $form[self::FORM_GROUP_CENTER_COMPOSED]->getData()); + $form[self::FORM_GROUP_CENTER_COMPOSED]->getData() + ); $user->addGroupCenter($groupCenter); if ($this->validator->validate($user)->count() === 0) { $em->flush(); - $this->addFlash('success', $this->get('translator')->trans('The ' + $this->addFlash('success', $this->get('translator')->trans('The ' . 'permissions have been successfully added to the user')); - return $this->redirect($this->generateUrl('admin_user_edit', - array('id' => $uid))); - } else { - foreach($this->validator->validate($user) as $error) + return $this->redirect($this->generateUrl( + 'admin_user_edit', + ['id' => $uid] + )); + } + + foreach ($this->validator->validate($user) as $error) { $this->addFlash('error', $error->getMessage()); } } - return $this->render('@ChillMain/User/edit.html.twig', array( - 'entity' => $user, - 'edit_form' => $this->createEditForm($user)->createView(), + return $this->render('@ChillMain/User/edit.html.twig', [ + 'entity' => $user, + 'edit_form' => $this->createEditForm($user)->createView(), 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(), 'delete_groupcenter_form' => array_map( - function(\Symfony\Component\Form\Form $form) { - return $form->createView(); - - }, - iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true)) - )); - } - - private function getPersistedGroupCenter(GroupCenter $groupCenter) - { - $em = $this->getDoctrine()->getManager(); - - $groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter') - ->findOneBy(array( - 'center' => $groupCenter->getCenter(), - 'permissionsGroup' => $groupCenter->getPermissionsGroup() - )); - - if (!$groupCenterManaged) { - $em->persist($groupCenter); - return $groupCenter; - } - - return $groupCenterManaged; + function (\Symfony\Component\Form\Form $form) { + return $form->createView(); + }, + iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true) + ), + ]); } /** - * Creates a form to edit a User entity. - * - * @param User $user The entity - * - * @return \Symfony\Component\Form\Form The form - */ - private function createEditForm(User $user) + * Creates a new User entity. + */ + public function createAction(Request $request) { - $form = $this->createForm(UserType::class, $user, array( - 'action' => $this->generateUrl('admin_user_update', array('id' => $user->getId())), - 'method' => 'PUT', - )); + $user = new User(); + $form = $this->createCreateForm($user); + $form->handleRequest($request); - $form->add('submit', SubmitType::class, array('label' => 'Update')); + if ($form->isValid()) { + $em = $this->getDoctrine()->getManager(); - return $form; + $user->setPassword($this->get('security.password_encoder') + ->encodePassword($user, $form['plainPassword']->getData())); + + $em->persist($user); + $em->flush(); + + return $this->redirect($this->generateUrl('admin_user_show', ['id' => $user->getId()])); + } + + return $this->render('@ChillMain/User/new.html.twig', [ + 'entity' => $user, + 'form' => $form->createView(), + ]); + } + + public function deleteLinkGroupCenterAction($uid, $gcid) + { + $em = $this->getDoctrine()->getManager(); + + $user = $em->getRepository('ChillMainBundle:User')->find($uid); + + if (!$user) { + throw $this->createNotFoundException('Unable to find User entity.'); + } + + $groupCenter = $em->getRepository('ChillMainBundle:GroupCenter') + ->find($gcid); + + if (!$groupCenter) { + throw $this->createNotFoundException('Unable to find groupCenter entity'); + } + + try { + $user->removeGroupCenter($groupCenter); + } catch (RuntimeException $ex) { + $this->addFlash('error', $this->get('translator')->trans($ex->getMessage())); + + return $this->redirect($this->generateUrl('admin_user_edit', ['id' => $uid])); + } + + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The permissions where removed.')); + + return $this->redirect($this->generateUrl('admin_user_edit', ['id' => $uid])); + } + + /** + * Displays a form to edit an existing User entity. + * + * @param mixed $id + */ + public function editAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $user = $em->getRepository('ChillMainBundle:User')->find($id); + + if (!$user) { + throw $this->createNotFoundException('Unable to find User entity.'); + } + + $editForm = $this->createEditForm($user); + + return $this->render('@ChillMain/User/edit.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView(), + 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(), + 'delete_groupcenter_form' => array_map( + function (\Symfony\Component\Form\Form $form) { + return $form->createView(); + }, + iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true) + ), + ]); + } + + /** + * Displays a form to edit the user password. + * + * @param mixed $id + */ + public function editPasswordAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $user = $em->getRepository('ChillMainBundle:User')->find($id); + + if (!$user) { + throw $this->createNotFoundException('Unable to find User entity.'); + } + + $editForm = $this->createEditPasswordForm($user); + + return $this->render('@ChillMain/User/edit_password.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView(), + ]); + } + + /** + * Lists all User entities. + */ + public function indexAction() + { + $em = $this->getDoctrine()->getManager(); + + $entities = $em->createQuery('SELECT u FROM ChillMainBundle:User u ' + . 'ORDER BY u.username') + ->getResult(); + + return $this->render('@ChillMain/User/index.html.twig', [ + 'entities' => $entities, + ]); + } + + /** + * Displays a form to create a new User entity. + */ + public function newAction() + { + $user = new User(); + $form = $this->createCreateForm($user); + + return $this->render('@ChillMain/User/new.html.twig', [ + 'entity' => $user, + 'form' => $form->createView(), + ]); + } + + /** + * Finds and displays a User entity. + * + * @param mixed $id + */ + public function showAction($id) + { + $em = $this->getDoctrine()->getManager(); + + $user = $em->getRepository('ChillMainBundle:User')->find($id); + + if (!$user) { + throw $this->createNotFoundException('Unable to find User entity.'); + } + + return $this->render('@ChillMain/User/show.html.twig', [ + 'entity' => $user, + ]); } /** * Edits an existing User entity. * + * @param mixed $id */ public function updateAction(Request $request, $id) { @@ -350,25 +280,26 @@ class UserController extends AbstractController if ($editForm->isValid()) { $em->flush(); - return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('admin_user_edit', ['id' => $id])); } - return $this->render('@ChillMain/User/edit.html.twig', array( - 'entity' => $user, - 'edit_form' => $editForm->createView(), + return $this->render('@ChillMain/User/edit.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView(), 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(), 'delete_groupcenter_form' => array_map( - function(\Symfony\Component\Form\Form $form) { - return $form->createView(); - - }, - iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true)) - )); + function (\Symfony\Component\Form\Form $form) { + return $form->createView(); + }, + iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true) + ), + ]); } /** - * Edits the user password + * Edits the user password. * + * @param mixed $id */ public function updatePasswordAction(Request $request, $id) { @@ -388,72 +319,138 @@ class UserController extends AbstractController // logging for prod $this->logger->info('update password for an user', [ - 'by' => $this->getUser()->getUsername(), - 'user' => $user->getUsername() - ]); + 'by' => $this->getUser()->getUsername(), + 'user' => $user->getUsername(), + ]); $user->setPassword($this->get('security.password_encoder') - ->encodePassword($user, $password)); + ->encodePassword($user, $password)); $em->flush(); $this->addFlash('success', $this->get('translator')->trans('Password successfully updated!')); - return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $id))); + return $this->redirect($this->generateUrl('admin_user_edit', ['id' => $id])); } - return $this->render('@ChillMain/User/edit_password.html.twig', array( - 'entity' => $user, - 'edit_form' => $editForm->createView(), - )); + return $this->render('@ChillMain/User/edit_password.html.twig', [ + 'entity' => $user, + 'edit_form' => $editForm->createView(), + ]); } + /** + * create a form to add a link to a groupcenter. + * + * @return \Symfony\Component\Form\Form + */ + private function createAddLinkGroupCenterForm(User $user) + { + return $this->createFormBuilder() + ->setAction($this->generateUrl( + 'admin_user_add_group_center', + ['uid' => $user->getId()] + )) + ->setMethod('POST') + ->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class) + ->add('submit', SubmitType::class, ['label' => 'Add a new groupCenter']) + ->getForm(); + } /** - * Creates a form to delete a link to a GroupCenter + * Creates a form to create a User entity. * - * @param mixed $permissionsGroup The entity id + * @param User $entity The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(User $entity) + { + $form = $this->createForm(UserType::class, $entity, [ + 'action' => $this->generateUrl('admin_user_create'), + 'method' => 'POST', + 'is_creation' => true, + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Create']); + + return $form; + } + + /** + * Creates a form to delete a link to a GroupCenter. * * @return \Symfony\Component\Form\Form The form */ private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter) { return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_delete_group_center', - array('uid' => $user->getId(), 'gcid' => $groupCenter->getId()))) + ->setAction($this->generateUrl( + 'admin_user_delete_group_center', + ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()] + )) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); } /** - * create a form to add a link to a groupcenter + * Creates a form to edit a User entity. * - * @param User $user + * @param User $user The entity + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(User $user) + { + $form = $this->createForm(UserType::class, $user, [ + 'action' => $this->generateUrl('admin_user_update', ['id' => $user->getId()]), + 'method' => 'PUT', + ]); + + $form->add('submit', SubmitType::class, ['label' => 'Update']); + + return $form; + } + + /** * @return \Symfony\Component\Form\Form */ - private function createAddLinkGroupCenterForm(User $user) + private function createEditPasswordForm(User $user) { - return $this->createFormBuilder() - ->setAction($this->generateUrl('admin_user_add_group_center', - array('uid' => $user->getId()))) - ->setMethod('POST') - ->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class) - ->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter')) - ->getForm() - ; + return $this->createForm(UserPasswordType::class, null, [ + 'action' => $this->generateUrl('admin_user_update_password', ['id' => $user->getId()]), + 'method' => 'PUT', + 'user' => $user, + ]) + ->add('submit', SubmitType::class, ['label' => 'Change password']) + ->remove('actual_password'); } - /** - * - * @param User $user - */ private function getDeleteLinkGroupCenterByUser(User $user) { foreach ($user->getGroupCenters() as $groupCenter) { yield $groupCenter->getId() => $this - ->createDeleteLinkGroupCenterForm($user, $groupCenter); + ->createDeleteLinkGroupCenterForm($user, $groupCenter); } } + + private function getPersistedGroupCenter(GroupCenter $groupCenter) + { + $em = $this->getDoctrine()->getManager(); + + $groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter') + ->findOneBy([ + 'center' => $groupCenter->getCenter(), + 'permissionsGroup' => $groupCenter->getPermissionsGroup(), + ]); + + if (!$groupCenterManaged) { + $em->persist($groupCenter); + + return $groupCenter; + } + + return $groupCenterManaged; + } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAddressReferences.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAddressReferences.php index 81bd1d909..cea5a7e0e 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAddressReferences.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadAddressReferences.php @@ -1,49 +1,85 @@ faker = \Faker\Factory::create('fr_FR'); } - /** - * - * @var ContainerInterface - */ - private $container; + public function getOrder() + { + return 51; + } - public function setContainer(ContainerInterface $container = null) + public function load(ObjectManager $manager) + { + echo "loading some reference address... \n"; + + for ($i = 0; 10 > $i; ++$i) { + $ar = $this->getRandomAddressReference(); + $manager->persist($ar); + } + + $manager->flush(); + } + + public function setContainer(?ContainerInterface $container = null) { $this->container = $container; } - public function getOrder() { - return 51; + /** + * Create a random reference address. + * + * @return AddressReference + */ + private function getRandomAddressReference() + { + $ar = new AddressReference(); + + $ar->setRefId($this->faker->numerify('ref-id-######')); + $ar->setStreet($this->faker->streetName); + $ar->setStreetNumber(rand(0, 199)); + $ar->setPoint($this->getRandomPoint()); + $ar->setPostcode($this->getReference( + LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)] + )); + + $ar->setMunicipalityCode($ar->getPostcode()->getCode()); + + return $ar; } - /** - * Create a random point + * Create a random point. * * @return Point */ @@ -53,43 +89,7 @@ class LoadAddressReferences extends AbstractFixture implements ContainerAwareInt $latBrussels = 50.84676; $lon = $lonBrussels + 0.01 * rand(-5, 5); $lat = $latBrussels + 0.01 * rand(-5, 5); + return Point::fromLonLat($lon, $lat); } - - /** - * Create a random reference address - * - * @return AddressReference - */ - private function getRandomAddressReference() - { - $ar= new AddressReference(); - - $ar->setRefId($this->faker->numerify('ref-id-######')); - $ar->setStreet($this->faker->streetName); - $ar->setStreetNumber(rand(0,199)); - $ar ->setPoint($this->getRandomPoint()); - $ar->setPostcode($this->getReference( - LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)] - )); - - $ar->setMunicipalityCode($ar->getPostcode()->getCode()); - - return $ar - ; - } - - public function load(ObjectManager $manager) { - - echo "loading some reference address... \n"; - - for ($i=0; $i<10; $i++) { - $ar = $this->getRandomAddressReference(); - $manager->persist($ar); - } - - $manager->flush(); - } - - } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCenters.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCenters.php index 1da1af2f3..6d2ed940f 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCenters.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCenters.php @@ -1,57 +1,39 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; +use Chill\MainBundle\Entity\Center; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Chill\MainBundle\Entity\Center; -/** - * - * - * @author Julien Fastré - */ class LoadCenters extends AbstractFixture implements OrderedFixtureInterface { + public static $centers = [ + [ + 'name' => 'Center A', + 'ref' => 'centerA', + ], + [ + 'name' => 'Center B', + 'ref' => 'centerB', + ], + ]; + + public static $refs = []; + public function getOrder() { return 100; } - - public static $centers = array( - array( - 'name' => 'Center A', - 'ref' => 'centerA' - ), - array( - 'name' => 'Center B', - 'ref' => 'centerB' - ) - ); - - public static $refs = array(); - + public function load(ObjectManager $manager) { foreach (static::$centers as $new) { @@ -62,7 +44,7 @@ class LoadCenters extends AbstractFixture implements OrderedFixtureInterface $this->addReference($new['ref'], $centerA); static::$refs[] = $new['ref']; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCountries.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCountries.php index 2405b4a98..e162b1d97 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCountries.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCountries.php @@ -1,48 +1,51 @@ + * Load countries into database. */ -class LoadCountries extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface { - +class LoadCountries extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface +{ /** - * * @var ContainerInterface */ private $container; - - public function setContainer(ContainerInterface $container = null) + + public function getOrder() + { + return 20; + } + + public function load(ObjectManager $manager) + { + echo "loading countries... \n"; + + $languages = $this->container->getParameter('chill_main.available_languages'); + + foreach (LoadCountriesCommand::prepareCountryList($languages) as $country) { + $manager->persist($country); + } + + $manager->flush(); + } + + public function setContainer(?ContainerInterface $container = null) { $this->container = $container; } - - public function getOrder() { - return 20; - } - - public function load(ObjectManager $manager) { - - echo "loading countries... \n"; - - $languages = $this->container->getParameter('chill_main.available_languages'); - - foreach (LoadCountriesCommand::prepareCountryList($languages) as $country){ - $manager->persist($country); - } - - $manager->flush(); - } - - } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadGroupCenters.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadGroupCenters.php index d44a3bbbf..4b1580324 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadGroupCenters.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadGroupCenters.php @@ -1,45 +1,27 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; +use Chill\MainBundle\Entity\GroupCenter; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Entity\GroupCenter; -use Chill\MainBundle\DataFixtures\ORM\LoadCenters; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -/** - * - * - * @author Julien Fastré - */ class LoadGroupCenters extends AbstractFixture implements OrderedFixtureInterface { + public static $refs = []; + public function getOrder() { return 500; } - - public static $refs = array(); public function load(ObjectManager $manager) { @@ -48,16 +30,16 @@ class LoadGroupCenters extends AbstractFixture implements OrderedFixtureInterfac $GroupCenter = new GroupCenter(); $GroupCenter->setCenter($this->getReference($centerRef)); $GroupCenter->setPermissionsGroup($this->getReference($permissionGroupRef)); - + $manager->persist($GroupCenter); - - $reference = $centerRef.'_'.$permissionGroupRef; + + $reference = $centerRef . '_' . $permissionGroupRef; $this->addReference($reference, $GroupCenter); static::$refs[] = $reference; - echo "Creating $reference... \n"; + echo "Creating {$reference}... \n"; } } - + $manager->flush(); } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php index a048b6b9f..fd52ddc9f 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadLanguages.php @@ -1,80 +1,82 @@ + * Load languages into database. */ class LoadLanguages extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface { - // The regional version of language are language with _ in the code - // This array contains regional code to not exclude - private $regionalVersionToInclude = ["ro_MD"]; - // Array of ancien languages (to exclude) - private $ancientToExclude = ["ang", "egy", "fro", "goh", "grc", "la", "non", "peo", "pro", "sga", - "dum", "enm", "frm", "gmh", "mga", "akk", "phn", "zxx", "got", "und"]; - + private $ancientToExclude = ['ang', 'egy', 'fro', 'goh', 'grc', 'la', 'non', 'peo', 'pro', 'sga', + 'dum', 'enm', 'frm', 'gmh', 'mga', 'akk', 'phn', 'zxx', 'got', 'und', ]; + /** - * * @var ContainerInterface */ private $container; - - public function setContainer(ContainerInterface $container = null) + + // The regional version of language are language with _ in the code + // This array contains regional code to not exclude + private $regionalVersionToInclude = ['ro_MD']; + + public function getOrder() { - $this->container = $container; - } - - public function getOrder() { return 10; } - - public function load(ObjectManager $manager) { - + + public function load(ObjectManager $manager) + { echo "loading languages... \n"; - + foreach (Intl::getLanguageBundle()->getLanguageNames() as $code => $language) { if ( !in_array($code, $this->regionalVersionToInclude) - && - !in_array($code, $this->ancientToExclude) - ) { - + && !in_array($code, $this->ancientToExclude) + ) { $lang = (new Language()) - ->setId($code) - ->setName($this->prepareName($code)) - ; + ->setId($code) + ->setName($this->prepareName($code)); $manager->persist($lang); } } - + $manager->flush(); } - + + public function setContainer(?ContainerInterface $container = null) + { + $this->container = $container; + } + /** - * prepare names for languages - * + * prepare names for languages. + * * @param string $languageCode + * * @return string[] languages name indexed by available language code */ - private function prepareName($languageCode) { + private function prepareName($languageCode) + { foreach ($this->container->getParameter('chill_main.available_languages') as $lang) { $names[$lang] = Intl::getLanguageBundle()->getLanguageName($languageCode); } - + return $names; } - - } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPermissionsGroup.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPermissionsGroup.php index 92d459aac..cffdf98d7 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPermissionsGroup.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPermissionsGroup.php @@ -1,87 +1,72 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; +use Chill\MainBundle\Entity\PermissionsGroup; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Entity\PermissionsGroup; -/** - * - * - * @author Julien Fastré - */ class LoadPermissionsGroup extends AbstractFixture implements OrderedFixtureInterface { + public static $permissionGroup = [ + [ + 'name' => 'social', + 'role_scopes' => [ + 'role_scope_CHILL_FOO_EDIT_social', + 'role_scope_CHILL_FOO_SEE_administrative', + 'role_scope_CHILL_FOO_EDIT_all', + ], + ], + [ + 'name' => 'administrative', + 'role_scopes' => [ + 'role_scope_CHILL_FOO_SEE_social', + 'role_scope_CHILL_FOO_EDIT_administrative', + 'role_scope_CHILL_FOO_EDIT_all', + ], + ], + [ + 'name' => 'direction', + 'role_scopes' => [ + 'role_scope_CHILL_FOO_EDIT_all', + 'role_scope_CHILL_FOO_SEE_DETAILS_social', + 'role_scope_CHILL_FOO_SEE_DETAILS_administrative', + ], + ], + ]; + + public static $refs = []; + public function getOrder() { return 400; } - - public static $permissionGroup = array( - array( - 'name' => 'social', - 'role_scopes' => array( - 'role_scope_CHILL_FOO_EDIT_social', - 'role_scope_CHILL_FOO_SEE_administrative', - "role_scope_CHILL_FOO_EDIT_all" - ) - ), - array( - 'name' => 'administrative', - 'role_scopes' => array( - "role_scope_CHILL_FOO_SEE_social", - "role_scope_CHILL_FOO_EDIT_administrative", - "role_scope_CHILL_FOO_EDIT_all" - ) - ), - array( - 'name' => 'direction', - 'role_scopes' => array( - "role_scope_CHILL_FOO_EDIT_all", - "role_scope_CHILL_FOO_SEE_DETAILS_social", - "role_scope_CHILL_FOO_SEE_DETAILS_administrative" - ) - ) - ); - - public static $refs = array(); public function load(ObjectManager $manager) { foreach (static::$permissionGroup as $new) { $permissionGroup = new PermissionsGroup(); $permissionGroup->setName($new['name']); + foreach ($new['role_scopes'] as $roleScopeRef) { $permissionGroup->addRoleScope($this->getReference($roleScopeRef)); } - + $manager->persist($permissionGroup); - $reference = 'permission_group_'.$new['name']; - echo "Creating $reference \n"; + $reference = 'permission_group_' . $new['name']; + echo "Creating {$reference} \n"; $this->setReference($reference, $permissionGroup); static::$refs[] = $reference; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php index 6e3d1781b..d983c93b0 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadPostalCodes.php @@ -1,105 +1,90 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; +use Chill\MainBundle\Entity\PostalCode; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Entity\PostalCode; + +use function strtolower; +use function ucwords; /** - * Description of LoadPostalCodes - * - * @author Julien Fastré - * @author Champs Libres + * Description of LoadPostalCodes. */ class LoadPostalCodes extends AbstractFixture implements OrderedFixtureInterface { + public static $refs = []; + + private static $codes = <<<'EOF' + 1000,BRUXELLES,BRUXELLES,Bruxelles + 1020,Laeken,BRUXELLES,Bruxelles + 1030,SCHAERBEEK,SCHAERBEEK,Bruxelles + 1040,ETTERBEEK,ETTERBEEK,Bruxelles + 1050,IXELLES,IXELLES,Bruxelles + 1060,SAINT-GILLES,SAINT-GILLES,Bruxelles + 1070,ANDERLECHT,ANDERLECHT,Bruxelles + 1080,MOLENBEEK-SAINT-JEAN,MOLENBEEK-SAINT-JEAN,Bruxelles + 1081,KOEKELBERG,KOEKELBERG,Bruxelles + 1082,BERCHEM-SAINTE-AGATHE,BERCHEM-SAINTE-AGATHE,Bruxelles + 1083,GANSHOREN,GANSHOREN,Bruxelles + 1090,JETTE,JETTE,Bruxelles + 1120,Neder-Over-Heembeek,BRUXELLES,Bruxelles + 1130,Haren,BRUXELLES,Bruxelles + 1140,EVERE,EVERE,Bruxelles + 1150,WOLUWE-SAINT-PIERRE,WOLUWE-SAINT-PIERRE,Bruxelles + 1160,AUDERGHEM,AUDERGHEM,Bruxelles + 1170,WATERMAEL-BOITSFORT,WATERMAEL-BOITSFORT,Bruxelles + 1180,UCCLE,UCCLE,Bruxelles + 1190,FOREST,FOREST,Bruxelles + 1200,WOLUWE-SAINT-LAMBERT,WOLUWE-SAINT-LAMBERT,Bruxelles + 1210,SAINT-JOSSE-TEN-NOODE,SAINT-JOSSE-TEN-NOODE,Bruxelles + 1300,Limal,WAVRE,Brabant-Wallon + 1300,WAVRE,WAVRE,Brabant-Wallon + 1301,Bierges,WAVRE,Brabant-Wallon + 1310,LA HULPE,LA HULPE,Brabant-Wallon + 1315,Glimes,INCOURT,Brabant-Wallon + 1315,INCOURT,INCOURT,Brabant-Wallon + 1315,Opprebais,INCOURT,Brabant-Wallon + 1315,Piètrebais,INCOURT,Brabant-Wallon + 1315,Roux-Miroir,INCOURT,Brabant-Wallon + 1320,BEAUVECHAIN,BEAUVECHAIN,Brabant-Wallon + EOF; + public function getOrder() { return 50; } - - public static $refs = array(); public function load(ObjectManager $manager) { $lines = str_getcsv(self::$codes, "\n"); $belgium = $manager->getRepository('ChillMainBundle:Country') - ->findOneBy(array('countryCode' => 'BE')); - - foreach($lines as $line) { - $code = str_getcsv($line); + ->findOneBy(['countryCode' => 'BE']); + + foreach ($lines as $line) { + $code = str_getcsv($line); $c = new PostalCode(); $c->setCountry($belgium) - ->setCode($code[0]) - ->setName(\ucwords(\strtolower($code[2]))) - ; + ->setCode($code[0]) + ->setName(ucwords(strtolower($code[2]))); $manager->persist($c); - $ref = 'postal_code_'.$code[0]; - - if (! $this->hasReference($ref)) { + $ref = 'postal_code_' . $code[0]; + + if (!$this->hasReference($ref)) { $this->addReference($ref, $c); self::$refs[] = $ref; } } - + $manager->flush(); } - - private static $codes = << - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; +use Chill\MainBundle\Entity\RoleScope; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; -/** - * - * - * @author Julien Fastré - */ class LoadRoleScopes extends AbstractFixture implements OrderedFixtureInterface { + public static $permissions = [ + 'CHILL_FOO_SEE' => [ + 'names' => [ + 'fr' => 'voir foo', + 'en' => 'see foo', + 'nl' => 'zie foo', + ], + ], + 'CHILL_FOO_SEE_DETAILS' => [ + 'names' => [ + 'fr' => 'voir foo avec détails', + 'en' => 'see foo with details', + 'nl' => 'zie foo in details', + ], + ], + 'CHILL_FOO_EDIT' => [ + 'names' => [ + 'fr' => 'modifier foo', + 'en' => 'edit foo', + 'nl' => 'editie foo', + ], + ], + ]; + + public static $references = []; + public function getOrder() { return 300; } - - public static $permissions = array( - 'CHILL_FOO_SEE' => array( - 'names' => array( - 'fr' => 'voir foo', - 'en' => 'see foo', - 'nl' => 'zie foo' - ) - ), - 'CHILL_FOO_SEE_DETAILS' => array( - 'names' => array( - 'fr' => 'voir foo avec détails', - 'en' => 'see foo with details', - 'nl' => 'zie foo in details' - ) - ), - 'CHILL_FOO_EDIT' => array( - 'names' => array( - 'fr' => 'modifier foo', - 'en' => 'edit foo', - 'nl' => 'editie foo' - ) - ) - ); - - public static $references = array(); public function load(ObjectManager $manager) { foreach (static::$permissions as $key => $permission) { - foreach(LoadScopes::$references as $scopeReference) { + foreach (LoadScopes::$references as $scopeReference) { $roleScope = new RoleScope(); $roleScope->setRole($key) - ->setScope($this->getReference($scopeReference)) - ; - $reference = 'role_scope_'.$key.'_'.$this->getReference($scopeReference)->getName()['en']; - echo "Creating $reference \n"; + ->setScope($this->getReference($scopeReference)); + $reference = 'role_scope_' . $key . '_' . $this->getReference($scopeReference)->getName()['en']; + echo "Creating {$reference} \n"; $this->addReference($reference, $roleScope); $manager->persist($roleScope); static::$references[] = $reference; } } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadScopes.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadScopes.php index 834de5e80..33a7b2d6b 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadScopes.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadScopes.php @@ -1,21 +1,10 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DataFixtures\ORM; @@ -25,55 +14,53 @@ use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; /** - * Create scopes - * - * @author Julien Fastré + * Create scopes. */ class LoadScopes extends AbstractFixture implements OrderedFixtureInterface { + public static $references = []; + + public $scopes = [ + [ + 'names' => [ + 'fr' => 'tous', + 'en' => 'all', + 'nl' => 'algemeen', + ], + ], + [ + 'names' => [ + 'fr' => 'social', + 'en' => 'social', + 'nl' => 'sociaal', + ], + ], + [ + 'names' => [ + 'fr' => 'administratif', + 'en' => 'administrative', + 'nl' => 'administratief', + ], + ], + ]; + public function getOrder() { return 200; } - - public $scopes = array( - array( - 'names' => array( - 'fr' => 'tous', - 'en' => 'all', - 'nl' => 'algemeen' - ), - ), - array( - 'names' => array( - 'fr' => 'social', - 'en' => 'social', - 'nl' => 'sociaal' - ) - ), - array( - 'names' => array( - 'fr' => 'administratif', - 'en' => 'administrative', - 'nl' => 'administratief' - ) - ) - ); - - public static $references = array(); public function load(ObjectManager $manager) - { + { foreach ($this->scopes as $new) { $scope = new \Chill\MainBundle\Entity\Scope(); $scope->setName($new['names']); - + $manager->persist($scope); - $reference = 'scope_'.$new['names']['en']; + $reference = 'scope_' . $new['names']['en']; $this->addReference($reference, $scope); static::$references[] = $reference; } - + $manager->flush(); } } diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php index 21b9341c7..74041e3a5 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadUsers.php @@ -1,91 +1,94 @@ */ class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { + public static $refs = [ + 'center a_social' => [ + 'groupCenterRefs' => ['centerA_permission_group_social'], + ], + 'center a_administrative' => [ + 'groupCenterRefs' => ['centerA_permission_group_administrative'], + ], + 'center a_direction' => [ + 'groupCenterRefs' => ['centerA_permission_group_direction'], + ], + 'center b_social' => [ + 'groupCenterRefs' => ['centerB_permission_group_social'], + ], + 'center b_administrative' => [ + 'groupCenterRefs' => ['centerB_permission_group_administrative'], + ], + 'center b_direction' => [ + 'groupCenterRefs' => ['centerB_permission_group_direction'], + ], + 'multi_center' => [ + 'groupCenterRefs' => ['centerA_permission_group_social', + 'centerB_permission_group_social', ], + ], + ]; + /** - * * @var ContainerInterface */ private $container; - + public function getOrder() { return 1000; } - - public static $refs = array( - 'center a_social' => array( - 'groupCenterRefs' => ['centerA_permission_group_social'] - ), - 'center a_administrative' => array( - 'groupCenterRefs' => ['centerA_permission_group_administrative'] - ), - 'center a_direction' => array( - 'groupCenterRefs' => ['centerA_permission_group_direction'] - ), - 'center b_social' => array( - 'groupCenterRefs' => ['centerB_permission_group_social'] - ), - 'center b_administrative' => array( - 'groupCenterRefs' => ['centerB_permission_group_administrative'] - ), - 'center b_direction' => array( - 'groupCenterRefs' => ['centerB_permission_group_direction'] - ), - 'multi_center' => array( - 'groupCenterRefs' => ['centerA_permission_group_social', - 'centerB_permission_group_social'] - ) - - ); public function load(ObjectManager $manager) { foreach (self::$refs as $username => $params) { - $user = new User(); $defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000); - + $encoderFactory = new EncoderFactory([ - User::class => $defaultEncoder + User::class => $defaultEncoder, ]); - + $user ->setUsername($username) - ->setPassword($encoderFactory - ->getEncoder($user) - ->encodePassword('password', $user->getSalt()) - ) - ->setEmail(sprintf("%s@chill.social", \str_replace(' ', '', $username))) - ; + ->setPassword( + $encoderFactory + ->getEncoder($user) + ->encodePassword('password', $user->getSalt()) + ) + ->setEmail(sprintf('%s@chill.social', str_replace(' ', '', $username))); foreach ($params['groupCenterRefs'] as $groupCenterRef) { $user->addGroupCenter($this->getReference($groupCenterRef)); } - - echo 'Creating user ' . $username ."... \n"; + + echo 'Creating user ' . $username . "... \n"; $manager->persist($user); $this->addReference($username, $user); } @@ -93,13 +96,12 @@ class LoadUsers extends AbstractFixture implements OrderedFixtureInterface, Cont $manager->flush(); } - public function setContainer(ContainerInterface $container = null) + public function setContainer(?ContainerInterface $container = null) { - if (NULL === $container) { - throw new \LogicException('$container should not be null'); + if (null === $container) { + throw new LogicException('$container should not be null'); } - + $this->container = $container; } - } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index a40221263..a98d4502b 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -1,65 +1,57 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader; -use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; -use Chill\MainBundle\DependencyInjection\Configuration; use Chill\MainBundle\Doctrine\DQL\GetJsonFieldByKey; -use Chill\MainBundle\Doctrine\DQL\Unaccent; use Chill\MainBundle\Doctrine\DQL\JsonAggregate; use Chill\MainBundle\Doctrine\DQL\JsonbExistsInArray; -use Chill\MainBundle\Doctrine\DQL\Similarity; use Chill\MainBundle\Doctrine\DQL\OverlapsI; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; use Chill\MainBundle\Doctrine\DQL\Replace; +use Chill\MainBundle\Doctrine\DQL\Similarity; +use Chill\MainBundle\Doctrine\DQL\Unaccent; +use Exception; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; +use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** * Class ChillMainExtension * This class load config for chillMainExtension. - * - * @package Chill\MainBundle\DependencyInjection */ -class ChillMainExtension extends Extension implements PrependExtensionInterface, +class ChillMainExtension extends Extension implements + PrependExtensionInterface, Widget\HasWidgetFactoriesExtensionInterface { /** - * widget factory + * widget factory. * * @var WidgetFactoryInterface[] */ - protected $widgetFactories = array(); + protected $widgetFactories = []; - /** - * @param WidgetFactoryInterface $factory - */ public function addWidgetFactory(WidgetFactoryInterface $factory) { $this->widgetFactories[] = $factory; } + /** + * @return \Chill\MainBundle\DependencyInjection\Configuration|object|\Symfony\Component\Config\Definition\ConfigurationInterface|null + */ + public function getConfiguration(array $config, ContainerBuilder $container) + { + return new Configuration($this->widgetFactories, $container); + } + /** * @return WidgetFactoryInterface[] */ @@ -69,10 +61,7 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, } /** - * {@inheritDoc} - * @param array $configs - * @param ContainerBuilder $container - * @throws \Exception + * @throws Exception */ public function load(array $configs, ContainerBuilder $container) { @@ -80,35 +69,50 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); - $container->setParameter('chill_main.installation_name', - $config['installation_name']); + $container->setParameter( + 'chill_main.installation_name', + $config['installation_name'] + ); - $container->setParameter('chill_main.available_languages', - $config['available_languages']); + $container->setParameter( + 'chill_main.available_languages', + $config['available_languages'] + ); - $container->setParameter('chill_main.routing.resources', - $config['routing']['resources']); + $container->setParameter( + 'chill_main.routing.resources', + $config['routing']['resources'] + ); - $container->setParameter('chill_main.pagination.item_per_page', - $config['pagination']['item_per_page']); + $container->setParameter( + 'chill_main.pagination.item_per_page', + $config['pagination']['item_per_page'] + ); - $container->setParameter('chill_main.notifications', - $config['notifications']); + $container->setParameter( + 'chill_main.notifications', + $config['notifications'] + ); - $container->setParameter('chill_main.redis', - $config['redis']); + $container->setParameter( + 'chill_main.redis', + $config['redis'] + ); - $container->setParameter('chill_main.phone_helper', - $config['phone_helper'] ?? []); + $container->setParameter( + 'chill_main.phone_helper', + $config['phone_helper'] ?? [] + ); // add the key 'widget' without the key 'enable' - $container->setParameter('chill_main.widgets', + $container->setParameter( + 'chill_main.widgets', isset($config['widgets']['homepage']) ? - array('homepage' => $config['widgets']['homepage']): - array() - ); + ['homepage' => $config['widgets']['homepage']] : + [] + ); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/doctrine.yaml'); $loader->load('services/logger.yaml'); @@ -133,97 +137,82 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface, $loader->load('services/search.yaml'); $loader->load('services/serializer.yaml'); - $this->configureCruds($container, $config['cruds'], $config['apis'], $loader); + $this->configureCruds($container, $config['cruds'], $config['apis'], $loader); } - /** - * @param array $config - * @param ContainerBuilder $container - * @return \Chill\MainBundle\DependencyInjection\Configuration|null|object|\Symfony\Component\Config\Definition\ConfigurationInterface - */ - public function getConfiguration(array $config, ContainerBuilder $container) - { - return new Configuration($this->widgetFactories, $container); - } - - /** - * @param ContainerBuilder $container - */ public function prepend(ContainerBuilder $container) { //add installation_name and date_format to globals $chillMainConfig = $container->getExtensionConfig($this->getAlias()); $config = $this->processConfiguration($this - ->getConfiguration($chillMainConfig, $container), $chillMainConfig); - $twigConfig = array( - 'globals' => array( - 'installation' => array( - 'name' => $config['installation_name']), - 'available_languages' => $config['available_languages'] - ), - 'form_themes' => array('@ChillMain/Form/fields.html.twig') - ); + ->getConfiguration($chillMainConfig, $container), $chillMainConfig); + $twigConfig = [ + 'globals' => [ + 'installation' => [ + 'name' => $config['installation_name'], ], + 'available_languages' => $config['available_languages'], + ], + 'form_themes' => ['@ChillMain/Form/fields.html.twig'], + ]; $container->prependExtensionConfig('twig', $twigConfig); //add DQL function to ORM (default entity_manager) - $container->prependExtensionConfig('doctrine', array( - 'orm' => array( - 'dql' => array( - 'string_functions' => array( - 'unaccent' => Unaccent::class, - 'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class, - 'AGGREGATE' => JsonAggregate::class, - 'REPLACE' => Replace::class, - ), - 'numeric_functions' => [ - 'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class, - 'SIMILARITY' => Similarity::class, - 'OVERLAPSI' => OverlapsI::class - ] - ) - ) - )); + $container->prependExtensionConfig('doctrine', [ + 'orm' => [ + 'dql' => [ + 'string_functions' => [ + 'unaccent' => Unaccent::class, + 'GET_JSON_FIELD_BY_KEY' => GetJsonFieldByKey::class, + 'AGGREGATE' => JsonAggregate::class, + 'REPLACE' => Replace::class, + ], + 'numeric_functions' => [ + 'JSONB_EXISTS_IN_ARRAY' => JsonbExistsInArray::class, + 'SIMILARITY' => Similarity::class, + 'OVERLAPSI' => OverlapsI::class, + ], + ], + ], + ]); //add dbal types (default entity_manager) - $container->prependExtensionConfig('doctrine', array( - 'dbal' => [ - 'types' => [ - 'dateinterval' => [ - 'class' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class - ], - 'point' => [ - 'class' => \Chill\MainBundle\Doctrine\Type\PointType::class - ] - ] - ] - )); + $container->prependExtensionConfig('doctrine', [ + 'dbal' => [ + 'types' => [ + 'dateinterval' => [ + 'class' => \Chill\MainBundle\Doctrine\Type\NativeDateIntervalType::class, + ], + 'point' => [ + 'class' => \Chill\MainBundle\Doctrine\Type\PointType::class, + ], + ], + ], + ]); //add current route to chill main - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillMainBundle/config/routes.yaml' - ) - - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillMainBundle/config/routes.yaml', + ], + ], + ]); //add a channel to log app events - $container->prependExtensionConfig('monolog', array( - 'channels' => array('chill') - )); + $container->prependExtensionConfig('monolog', [ + 'channels' => ['chill'], + ]); } /** - * Load parameter for configuration and set parameters for api + * Load parameter for configuration and set parameters for api. */ protected function configureCruds( ContainerBuilder $container, array $crudConfig, array $apiConfig, Loader\YamlFileLoader $loader - ): void - { + ): void { if (count($crudConfig) === 0) { return; } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php index 9197ddb83..facc3cdf7 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ACLFlagsCompilerPass.php @@ -1,37 +1,44 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\DependencyInjection\CompilerPass; + +use Chill\MainBundle\Form\PermissionsGroupType; +use LogicalException; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + class ACLFlagsCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $permissionGroupType = $container->getDefinition(PermissionsGroupType::class); - - foreach($container->findTaggedServiceIds('chill_main.flags') as $id => $tags) { + + foreach ($container->findTaggedServiceIds('chill_main.flags') as $id => $tags) { $reference = new Reference($id); - + foreach ($tags as $tag) { - switch($tag['scope']) { + switch ($tag['scope']) { case PermissionsGroupType::FLAG_SCOPE: - - $permissionGroupType->addMethodCall('addFlagProvider', [ $reference ]); + $permissionGroupType->addMethodCall('addFlagProvider', [$reference]); + break; + default: - throw new \LogicalException(sprintf( - "This tag 'scope' is not implemented: %s, on service with id %s", $tag['scope'], $id) - ); + throw new LogicalException( + sprintf( + "This tag 'scope' is not implemented: %s, on service with id %s", + $tag['scope'], + $id + ) + ); } } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ExportsCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ExportsCompilerPass.php index 2aa5327b0..f91cfe126 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ExportsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/ExportsCompilerPass.php @@ -1,51 +1,38 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\CompilerPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use LogicException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; /** - * Compiles the services tagged with : - * + * Compiles the services tagged with :. + * * - chill.export * - chill.export_formatter * - chill.export_aggregator * - chill.export_filter * - chill.export_elements_provider - * - * - * @author Julien Fastré */ class ExportsCompilerPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) { if (!$container->has('Chill\MainBundle\Export\ExportManager')) { - throw new \LogicException('service Chill\MainBundle\Export\ExportManager ' + throw new LogicException('service Chill\MainBundle\Export\ExportManager ' . 'is not defined. It is required by ExportsCompilerPass'); } - + $chillManagerDefinition = $container->findDefinition( 'Chill\MainBundle\Export\ExportManager' ); @@ -56,155 +43,159 @@ class ExportsCompilerPass implements CompilerPassInterface $this->compileFormatters($chillManagerDefinition, $container); $this->compileExportElementsProvider($chillManagerDefinition, $container); } - - private function compileExports(Definition $chillManagerDefinition, - ContainerBuilder $container) - { - $taggedServices = $container->findTaggedServiceIds( - 'chill.export' - ); - - $knownAliases = array(); - - foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - if (!isset($attributes["alias"])) { - throw new \LogicException("the 'alias' attribute is missing in your ". - "service '$id' definition"); - } - - if (array_search($attributes["alias"], $knownAliases)) { - throw new \LogicException("There is already a chill.export service with alias " - .$attributes["alias"].". Choose another alias."); - } - $knownAliases[] = $attributes["alias"]; - - $chillManagerDefinition->addMethodCall( - 'addExport', - array(new Reference($id), $attributes["alias"]) - ); - } - } - } - - private function compileFilters(Definition $chillManagerDefinition, - ContainerBuilder $container) - { - $taggedServices = $container->findTaggedServiceIds( - 'chill.export_filter' - ); - - $knownAliases = array(); - - foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - if (!isset($attributes["alias"])) { - throw new \LogicException("the 'alias' attribute is missing in your ". - "service '$id' definition"); - } - - if (array_search($attributes["alias"], $knownAliases)) { - throw new \LogicException("There is already a chill.export_filter service with alias " - .$attributes["alias"].". Choose another alias."); - } - $knownAliases[] = $attributes["alias"]; - - $chillManagerDefinition->addMethodCall( - 'addFilter', - array(new Reference($id), $attributes["alias"]) - ); - } - } - } - - private function compileAggregators(Definition $chillManagerDefinition, - ContainerBuilder $container) - { + + private function compileAggregators( + Definition $chillManagerDefinition, + ContainerBuilder $container + ) { $taggedServices = $container->findTaggedServiceIds( 'chill.export_aggregator' ); - - $knownAliases = array(); - + + $knownAliases = []; + foreach ($taggedServices as $id => $tagAttributes) { foreach ($tagAttributes as $attributes) { - if (!isset($attributes["alias"])) { - throw new \LogicException("the 'alias' attribute is missing in your ". - "service '$id' definition"); + if (!isset($attributes['alias'])) { + throw new LogicException("the 'alias' attribute is missing in your " . + "service '{$id}' definition"); } - - if (array_search($attributes["alias"], $knownAliases)) { - throw new \LogicException("There is already a chill.export_aggregator service with alias " - .$attributes["alias"].". Choose another alias."); + + if (array_search($attributes['alias'], $knownAliases)) { + throw new LogicException('There is already a chill.export_aggregator service with alias ' + . $attributes['alias'] . '. Choose another alias.'); } - $knownAliases[] = $attributes["alias"]; - + $knownAliases[] = $attributes['alias']; + $chillManagerDefinition->addMethodCall( 'addAggregator', - array(new Reference($id), $attributes["alias"]) - ); - } - } - } - - private function compileFormatters(Definition $chillManagerDefinition, - ContainerBuilder $container) - { - $taggedServices = $container->findTaggedServiceIds( - 'chill.export_formatter' - ); - - $knownAliases = array(); - - foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - if (!isset($attributes["alias"])) { - throw new \LogicException("the 'alias' attribute is missing in your ". - "service '$id' definition"); - } - - if (array_search($attributes["alias"], $knownAliases)) { - throw new \LogicException("There is already a chill.export_formatter service with alias " - .$attributes["alias"].". Choose another alias."); - } - $knownAliases[] = $attributes["alias"]; - - $chillManagerDefinition->addMethodCall( - 'addFormatter', - array(new Reference($id), $attributes["alias"]) - ); - } - } - } - - private function compileExportElementsProvider(Definition $chillManagerDefinition, - ContainerBuilder $container) - { - $taggedServices = $container->findTaggedServiceIds( - 'chill.export_elements_provider' - ); - - $knownAliases = array(); - - foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - if (!isset($attributes["prefix"])) { - throw new \LogicException("the 'prefix' attribute is missing in your ". - "service '$id' definition"); - } - - if (array_search($attributes["prefix"], $knownAliases)) { - throw new \LogicException("There is already a chill.export_elements_provider service with prefix " - .$attributes["prefix"].". Choose another prefix."); - } - $knownAliases[] = $attributes["prefix"]; - - $chillManagerDefinition->addMethodCall( - 'addExportElementsProvider', - array(new Reference($id), $attributes["prefix"]) + [new Reference($id), $attributes['alias']] ); } } } + private function compileExportElementsProvider( + Definition $chillManagerDefinition, + ContainerBuilder $container + ) { + $taggedServices = $container->findTaggedServiceIds( + 'chill.export_elements_provider' + ); + + $knownAliases = []; + + foreach ($taggedServices as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + if (!isset($attributes['prefix'])) { + throw new LogicException("the 'prefix' attribute is missing in your " . + "service '{$id}' definition"); + } + + if (array_search($attributes['prefix'], $knownAliases)) { + throw new LogicException('There is already a chill.export_elements_provider service with prefix ' + . $attributes['prefix'] . '. Choose another prefix.'); + } + $knownAliases[] = $attributes['prefix']; + + $chillManagerDefinition->addMethodCall( + 'addExportElementsProvider', + [new Reference($id), $attributes['prefix']] + ); + } + } + } + + private function compileExports( + Definition $chillManagerDefinition, + ContainerBuilder $container + ) { + $taggedServices = $container->findTaggedServiceIds( + 'chill.export' + ); + + $knownAliases = []; + + foreach ($taggedServices as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + if (!isset($attributes['alias'])) { + throw new LogicException("the 'alias' attribute is missing in your " . + "service '{$id}' definition"); + } + + if (array_search($attributes['alias'], $knownAliases)) { + throw new LogicException('There is already a chill.export service with alias ' + . $attributes['alias'] . '. Choose another alias.'); + } + $knownAliases[] = $attributes['alias']; + + $chillManagerDefinition->addMethodCall( + 'addExport', + [new Reference($id), $attributes['alias']] + ); + } + } + } + + private function compileFilters( + Definition $chillManagerDefinition, + ContainerBuilder $container + ) { + $taggedServices = $container->findTaggedServiceIds( + 'chill.export_filter' + ); + + $knownAliases = []; + + foreach ($taggedServices as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + if (!isset($attributes['alias'])) { + throw new LogicException("the 'alias' attribute is missing in your " . + "service '{$id}' definition"); + } + + if (array_search($attributes['alias'], $knownAliases)) { + throw new LogicException('There is already a chill.export_filter service with alias ' + . $attributes['alias'] . '. Choose another alias.'); + } + $knownAliases[] = $attributes['alias']; + + $chillManagerDefinition->addMethodCall( + 'addFilter', + [new Reference($id), $attributes['alias']] + ); + } + } + } + + private function compileFormatters( + Definition $chillManagerDefinition, + ContainerBuilder $container + ) { + $taggedServices = $container->findTaggedServiceIds( + 'chill.export_formatter' + ); + + $knownAliases = []; + + foreach ($taggedServices as $id => $tagAttributes) { + foreach ($tagAttributes as $attributes) { + if (!isset($attributes['alias'])) { + throw new LogicException("the 'alias' attribute is missing in your " . + "service '{$id}' definition"); + } + + if (array_search($attributes['alias'], $knownAliases)) { + throw new LogicException('There is already a chill.export_formatter service with alias ' + . $attributes['alias'] . '. Choose another alias.'); + } + $knownAliases[] = $attributes['alias']; + + $chillManagerDefinition->addMethodCall( + 'addFormatter', + [new Reference($id), $attributes['alias']] + ); + } + } + } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/GroupingCenterCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/GroupingCenterCompilerPass.php index 3239e7045..7a361f0e0 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/GroupingCenterCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/GroupingCenterCompilerPass.php @@ -1,46 +1,35 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\DependencyInjection\CompilerPass; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Reference; -use Chill\MainBundle\Form\Type\Export\PickCenterType; /** - * + * Chill is a software for social workers * - * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\DependencyInjection\CompilerPass; + +use LogicException; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + class GroupingCenterCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { - if (FALSE === $container->hasDefinition('chill.main.form.pick_centers_type')) { - throw new \LogicException("The service chill.main.form.pick_centers_type does " - . "not exists in container"); + if (false === $container->hasDefinition('chill.main.form.pick_centers_type')) { + throw new LogicException('The service chill.main.form.pick_centers_type does ' + . 'not exists in container'); } - + $pickCenterType = $container->getDefinition('chill.main.form.pick_centers_type'); - + foreach ($container->findTaggedServiceIds('chill.grouping_center') as $serviceId => $tagged) { - $pickCenterType->addMethodCall('addGroupingCenter', - [ new Reference($serviceId) ]); + $pickCenterType->addMethodCall( + 'addGroupingCenter', + [new Reference($serviceId)] + ); } } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/MenuCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/MenuCompilerPass.php index a8d87d950..34cd6246e 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/MenuCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/MenuCompilerPass.php @@ -1,44 +1,33 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\DependencyInjection\CompilerPass; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Reference; -use Chill\MainBundle\Routing\MenuComposer; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\DependencyInjection\CompilerPass; + +use Chill\MainBundle\Routing\MenuComposer; +use LogicException; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + class MenuCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { - if (!$container->hasDefinition('chill.main.menu_composer')) { - throw new \LogicException(sprintf("The service %s does not exists in " - . "container.", MenuComposer::class)); + if (!$container->hasDefinition('chill.main.menu_composer')) { + throw new LogicException(sprintf('The service %s does not exists in ' + . 'container.', MenuComposer::class)); } - + $menuComposerDefinition = $container->getDefinition('chill.main.menu_composer'); $services = []; + foreach ($container->findTaggedServiceIds('chill.menu_builder') as $id => $tags) { $services[] = [ 'id' => $id, @@ -50,11 +39,13 @@ class MenuCompilerPass implements CompilerPassInterface if ($a['priority'] == $b['priority']) { return 0; } + return ($a['priority'] < $b['priority']) ? -1 : 1; }); foreach ($services as $service) { $class = $container->getDefinition($service['id'])->getClass(); + foreach ($class::getMenuIds() as $menuId) { $menuComposerDefinition ->addMethodCall('addLocalMenuBuilder', [new Reference($service['id']), $menuId]); diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/NotificationCounterCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/NotificationCounterCompilerPass.php index 941aeeb7a..3092c3ee6 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/NotificationCounterCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/NotificationCounterCompilerPass.php @@ -1,43 +1,31 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\DependencyInjection\CompilerPass; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Chill\MainBundle\Templating\UI\CountNotificationUser; -use Symfony\Component\DependencyInjection\Reference; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\DependencyInjection\CompilerPass; + +use Chill\MainBundle\Templating\UI\CountNotificationUser; +use LogicException; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + class NotificationCounterCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasDefinition(CountNotificationUser::class)) { - throw new \LogicException("The service ".CountNotificationUser::class." " - . "should be defined"); + throw new LogicException('The service ' . CountNotificationUser::class . ' ' + . 'should be defined'); } - + $notificationCounterDefinition = $container->getDefinition(CountNotificationUser::class); - + foreach ($container->findTaggedServiceIds('chill.count_notification.user') as $id => $tags) { $notificationCounterDefinition ->addMethodCall('addNotificationCounter', [new Reference($id)]); diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/SearchableServicesCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/SearchableServicesCompilerPass.php index e07849ed2..756438e71 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/SearchableServicesCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/SearchableServicesCompilerPass.php @@ -1,32 +1,21 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\DependencyInjection\CompilerPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use LogicException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; class SearchableServicesCompilerPass implements CompilerPassInterface { - /* * (non-PHPdoc) * @see \Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface::process() @@ -34,10 +23,10 @@ class SearchableServicesCompilerPass implements CompilerPassInterface public function process(ContainerBuilder $container) { if (!$container->hasDefinition('chill_main.search_provider')) { - throw new \LogicException('service chill_main.search_provider ' + throw new LogicException('service chill_main.search_provider ' . 'is not defined.'); } - + $definition = $container->getDefinition( 'chill_main.search_provider' ); @@ -45,29 +34,27 @@ class SearchableServicesCompilerPass implements CompilerPassInterface $taggedServices = $container->findTaggedServiceIds( 'chill.search' ); - - $knownAliases = array(); - + + $knownAliases = []; + foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - - if (!isset($attributes["alias"])) { - throw new \LogicException("the 'name' attribute is missing in your ". - "service '$id' definition"); + if (!isset($attributes['alias'])) { + throw new LogicException("the 'name' attribute is missing in your " . + "service '{$id}' definition"); } - - if (array_search($attributes["alias"], $knownAliases)) { - throw new \LogicException("There is already a chill.search service with alias " - .$attributes["alias"].". Choose another alias."); + + if (array_search($attributes['alias'], $knownAliases)) { + throw new LogicException('There is already a chill.search service with alias ' + . $attributes['alias'] . '. Choose another alias.'); } - $knownAliases[] = $attributes["alias"]; - + $knownAliases[] = $attributes['alias']; + $definition->addMethodCall( 'addSearchService', - array(new Reference($id), $attributes["alias"]) + [new Reference($id), $attributes['alias']] ); } } } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/TimelineCompilerClass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/TimelineCompilerClass.php index d5b8efbde..246a81a1a 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/TimelineCompilerClass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/TimelineCompilerClass.php @@ -1,42 +1,32 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\CompilerPass; +use LogicException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** - * Add services taggued with `name: chill.timeline` to - * timeline_builder service definition - * + * Add services taggued with `name: chill.timeline` to + * timeline_builder service definition. */ class TimelineCompilerClass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasDefinition('chill_main.timeline_builder')) { - throw new \LogicException('service chill_main.timeline_builder ' + throw new LogicException('service chill_main.timeline_builder ' . 'is not defined.'); } - + $definition = $container->getDefinition( 'chill_main.timeline_builder' ); @@ -44,22 +34,19 @@ class TimelineCompilerClass implements CompilerPassInterface $taggedServices = $container->findTaggedServiceIds( 'chill.timeline' ); - + foreach ($taggedServices as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - - if (!isset($attributes["context"])) { - throw new \LogicException("the 'context' attribute is missing in your ". - "service '$id' definition"); + if (!isset($attributes['context'])) { + throw new LogicException("the 'context' attribute is missing in your " . + "service '{$id}' definition"); } $definition->addMethodCall( 'addProvider', - array($attributes["context"], $id, new Reference($id)) + [$attributes['context'], $id, new Reference($id)] ); } } } - } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/WidgetsCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/WidgetsCompilerPass.php index b28b8fdbb..2fd9416c4 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/WidgetsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/CompilerPass/WidgetsCompilerPass.php @@ -1,34 +1,24 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\CompilerPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Compile the service definition to register widgets. - * */ -class WidgetsCompilerPass extends AbstractWidgetsCompilerPass { - - public function process(ContainerBuilder $container) - { - $this->doProcess($container, 'chill_main', 'chill_main.widgets'); - } +class WidgetsCompilerPass extends AbstractWidgetsCompilerPass +{ + public function process(ContainerBuilder $container) + { + $this->doProcess($container, 'chill_main', 'chill_main.widgets'); + } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ConfigConsistencyCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/ConfigConsistencyCompilerPass.php index 3331b29bb..17a9a0422 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ConfigConsistencyCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ConfigConsistencyCompilerPass.php @@ -1,59 +1,52 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection; +use LogicException; +use RuntimeException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** - * Description of ConfigConsistencyCompilerPass - * - * @author Julien Fastré + * Description of ConfigConsistencyCompilerPass. */ class ConfigConsistencyCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $availableLanguages = $container - ->getParameter('chill_main.available_languages'); + ->getParameter('chill_main.available_languages'); $methodCallsTranslator = $container - ->findDefinition('translator.default') - ->getMethodCalls(); - - $fallbackLocales = array(); - foreach($methodCallsTranslator as $call) { - if ($call[0] === 'setFallbackLocales') { - $fallbackLocales = array_merge($fallbackLocales, - $call[1][0]); - } + ->findDefinition('translator.default') + ->getMethodCalls(); + + $fallbackLocales = []; + + foreach ($methodCallsTranslator as $call) { + if ('setFallbackLocales' === $call[0]) { + $fallbackLocales = array_merge( + $fallbackLocales, + $call[1][0] + ); + } } - + if (count($fallbackLocales) === 0) { - throw new \LogicException('the fallback locale are not defined. ' + throw new LogicException('the fallback locale are not defined. ' . 'The framework config should not allow this.'); } - + $diff = array_diff($fallbackLocales, $availableLanguages); + if (count($diff) > 0) { - throw new \RuntimeException(sprintf('The chill_main.available_languages' + throw new RuntimeException(sprintf('The chill_main.available_languages' . ' parameter does not contains fallback locales. The languages %s' . ' are missing.', implode(', ', $diff))); } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index c7e4c00ef..c37d4f489 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -1,41 +1,40 @@ setWidgetFactories($widgetFactories); $this->containerBuilder = $containerBuilder; } - - /** - * {@inheritDoc} - */ + public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder('chill_main'); @@ -43,209 +42,203 @@ class Configuration implements ConfigurationInterface $rootNode ->children() - ->scalarNode('installation_name') - ->cannotBeEmpty() - ->defaultValue('Chill') - ->end() // end of scalar 'installation_name' - ->arrayNode('available_languages') - ->defaultValue(array('fr')) - ->prototype('scalar')->end() - ->end() // end of array 'available_languages' - ->arrayNode('routing') - ->children() - ->arrayNode('resources') - ->prototype('scalar')->end() - ->end() // end of array 'resources' - ->end() // end of children - ->end() // end of array node 'routing' - ->arrayNode('pagination') - ->canBeDisabled() - ->children() - ->integerNode('item_per_page') - ->info('The number of item to show in the page result, by default') - ->min(1) - ->defaultValue(50) - ->end() // end of integer 'item_per_page' - ->end() // end of children - ->end() // end of pagination - ->arrayNode('notifications') - ->children() - ->scalarNode('from_email') - ->cannotBeEmpty() - ->end() - ->scalarNode('from_name') - ->cannotBeEmpty() - ->end() - ->enumNode('scheme') - ->cannotBeEmpty() - ->values(['http', 'https']) - ->defaultValue('https') - ->end() - ->scalarNode('host') - ->cannotBeEmpty() - ->end() - ->end() - ->end() // end of notifications - ->arrayNode('phone_helper') - ->canBeUnset() - ->children() - ->scalarNode('twilio_sid') - ->defaultNull() - ->end() - ->scalarNode('twilio_secret') - ->defaultNull() - ->end() - ->end() - ->end() - ->arrayNode('redis') - ->children() - ->scalarNode('host') - ->cannotBeEmpty() - ->end() - ->scalarNode('port') - ->defaultValue(6379) - ->end() - ->scalarNode('timeout') - ->defaultValue(1) - ->end() - ->end() - ->end() - ->arrayNode('widgets') - ->canBeEnabled() - ->canBeUnset() - ->children() - ->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder)) - ->end() // end of widgets/children - ->end() // end of widgets - ->arrayNode('cruds') - ->defaultValue([]) - ->arrayPrototype() - ->children() - ->scalarNode('class')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('controller') - ->cannotBeEmpty() - ->defaultValue(\Chill\MainBundle\CRUD\Controller\CRUDController::class) - ->end() - ->scalarNode('name')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('base_role')->defaultNull()->end() - ->scalarNode('form_class')->defaultNull()->end() - ->arrayNode('actions') - ->defaultValue([ - 'edit' => [], - 'new' => [] - ]) - ->useAttributeAsKey('name') - ->arrayPrototype() - ->children() - ->scalarNode('controller_action') - ->defaultNull() - ->info('the method name to call in the route. Will be set to the action name if left empty.') - ->example("action") - ->end() - ->scalarNode('path') - ->defaultNull() - ->info('the path that will be **appended** after the base path. Do not forget to add ' + ->scalarNode('installation_name') + ->cannotBeEmpty() + ->defaultValue('Chill') + ->end() // end of scalar 'installation_name' + ->arrayNode('available_languages') + ->defaultValue(['fr']) + ->prototype('scalar')->end() + ->end() // end of array 'available_languages' + ->arrayNode('routing') + ->children() + ->arrayNode('resources') + ->prototype('scalar')->end() + ->end() // end of array 'resources' + ->end() // end of children + ->end() // end of array node 'routing' + ->arrayNode('pagination') + ->canBeDisabled() + ->children() + ->integerNode('item_per_page') + ->info('The number of item to show in the page result, by default') + ->min(1) + ->defaultValue(50) + ->end() // end of integer 'item_per_page' + ->end() // end of children + ->end() // end of pagination + ->arrayNode('notifications') + ->children() + ->scalarNode('from_email') + ->cannotBeEmpty() + ->end() + ->scalarNode('from_name') + ->cannotBeEmpty() + ->end() + ->enumNode('scheme') + ->cannotBeEmpty() + ->values(['http', 'https']) + ->defaultValue('https') + ->end() + ->scalarNode('host') + ->cannotBeEmpty() + ->end() + ->end() + ->end() // end of notifications + ->arrayNode('phone_helper') + ->canBeUnset() + ->children() + ->scalarNode('twilio_sid') + ->defaultNull() + ->end() + ->scalarNode('twilio_secret') + ->defaultNull() + ->end() + ->end() + ->end() + ->arrayNode('redis') + ->children() + ->scalarNode('host') + ->cannotBeEmpty() + ->end() + ->scalarNode('port') + ->defaultValue(6379) + ->end() + ->scalarNode('timeout') + ->defaultValue(1) + ->end() + ->end() + ->end() + ->arrayNode('widgets') + ->canBeEnabled() + ->canBeUnset() + ->children() + ->append($this->addWidgetsConfiguration('homepage', $this->containerBuilder)) + ->end() // end of widgets/children + ->end() // end of widgets + ->arrayNode('cruds') + ->defaultValue([]) + ->arrayPrototype() + ->children() + ->scalarNode('class')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('controller') + ->cannotBeEmpty() + ->defaultValue(\Chill\MainBundle\CRUD\Controller\CRUDController::class) + ->end() + ->scalarNode('name')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('base_role')->defaultNull()->end() + ->scalarNode('form_class')->defaultNull()->end() + ->arrayNode('actions') + ->defaultValue([ + 'edit' => [], + 'new' => [], + ]) + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->scalarNode('controller_action') + ->defaultNull() + ->info('the method name to call in the route. Will be set to the action name if left empty.') + ->example('action') + ->end() + ->scalarNode('path') + ->defaultNull() + ->info('the path that will be **appended** after the base path. Do not forget to add ' . 'arguments for the method. Will be set to the action name, including an `{id}` ' . 'parameter if left empty.') - ->example('/{id}/my-action') - ->end() - ->arrayNode('requirements') - ->ignoreExtraKeys(false) - ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.') - ->end() - ->scalarNode('role') - ->defaultNull() - ->info('the role that will be required for this action. Override option `base_role`') - ->end() - ->scalarNode('template') - ->defaultNull() - ->info('the template to render the view') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - - ->end() - - - ->arrayNode('apis') - ->defaultValue([]) - ->arrayPrototype() - ->children() - ->scalarNode('class')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('controller') - ->cannotBeEmpty() - ->defaultValue(\Chill\MainBundle\CRUD\Controller\ApiController::class) - ->end() - ->scalarNode('name')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end() - ->scalarNode('base_role')->defaultNull()->end() - ->arrayNode('actions') - ->useAttributeAsKey('name') - ->arrayPrototype() - ->children() - ->scalarNode('controller_action') - ->defaultNull() - ->info('the method name to call in the controller. Will be set to the concatenation '. + ->example('/{id}/my-action') + ->end() + ->arrayNode('requirements') + ->ignoreExtraKeys(false) + ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.') + ->end() + ->scalarNode('role') + ->defaultNull() + ->info('the role that will be required for this action. Override option `base_role`') + ->end() + ->scalarNode('template') + ->defaultNull() + ->info('the template to render the view') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->arrayNode('apis') + ->defaultValue([]) + ->arrayPrototype() + ->children() + ->scalarNode('class')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('controller') + ->cannotBeEmpty() + ->defaultValue(\Chill\MainBundle\CRUD\Controller\ApiController::class) + ->end() + ->scalarNode('name')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('base_path')->cannotBeEmpty()->isRequired()->end() + ->scalarNode('base_role')->defaultNull()->end() + ->arrayNode('actions') + ->useAttributeAsKey('name') + ->arrayPrototype() + ->children() + ->scalarNode('controller_action') + ->defaultNull() + ->info('the method name to call in the controller. Will be set to the concatenation ' . 'of action name + \'Api\' if left empty.') - ->example("showApi") - ->end() - ->scalarNode('path') - ->defaultNull() - ->info('the path that will be **appended** after the base path. Do not forget to add ' . - 'arguments for the method. By default, will set to the action name, including an `{id}` '. - 'parameter. A suffix of action name will be appended, except if the action name '. + ->example('showApi') + ->end() + ->scalarNode('path') + ->defaultNull() + ->info('the path that will be **appended** after the base path. Do not forget to add ' . + 'arguments for the method. By default, will set to the action name, including an `{id}` ' . + 'parameter. A suffix of action name will be appended, except if the action name ' . 'is "_entity".') - ->example('/{id}/my-action') - ->end() - ->arrayNode('requirements') - ->ignoreExtraKeys(false) - ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.') - ->end() - ->enumNode('single-collection') - ->values(['single', 'collection']) - ->defaultValue('single') - ->info('indicates if the returned object is a single element or a collection. '. - 'If the action name is `_index`, this value will always be considered as '. + ->example('/{id}/my-action') + ->end() + ->arrayNode('requirements') + ->ignoreExtraKeys(false) + ->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.') + ->end() + ->enumNode('single-collection') + ->values(['single', 'collection']) + ->defaultValue('single') + ->info('indicates if the returned object is a single element or a collection. ' . + 'If the action name is `_index`, this value will always be considered as ' . '`collection`') - ->end() - ->arrayNode('methods') - ->addDefaultsIfNotSet() - ->info('the allowed methods') - ->children() - ->booleanNode(Request::METHOD_GET)->defaultTrue()->end() - ->booleanNode(Request::METHOD_HEAD)->defaultTrue()->end() - ->booleanNode(Request::METHOD_POST)->defaultFalse()->end() - ->booleanNode(Request::METHOD_DELETE)->defaultFalse()->end() - ->booleanNode(Request::METHOD_PUT)->defaultFalse()->end() - ->end() - ->end() - ->arrayNode('roles') - ->addDefaultsIfNotSet() - ->info("The role require for each http method") - ->children() - ->scalarNode(Request::METHOD_GET)->defaultNull()->end() - ->scalarNode(Request::METHOD_HEAD)->defaultNull()->end() - ->scalarNode(Request::METHOD_POST)->defaultNull()->end() - ->scalarNode(Request::METHOD_DELETE)->defaultNull()->end() - ->scalarNode(Request::METHOD_PUT)->defaultNull()->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() + ->end() + ->arrayNode('methods') + ->addDefaultsIfNotSet() + ->info('the allowed methods') + ->children() + ->booleanNode(Request::METHOD_GET)->defaultTrue()->end() + ->booleanNode(Request::METHOD_HEAD)->defaultTrue()->end() + ->booleanNode(Request::METHOD_POST)->defaultFalse()->end() + ->booleanNode(Request::METHOD_DELETE)->defaultFalse()->end() + ->booleanNode(Request::METHOD_PUT)->defaultFalse()->end() + ->end() + ->end() + ->arrayNode('roles') + ->addDefaultsIfNotSet() + ->info('The role require for each http method') + ->children() + ->scalarNode(Request::METHOD_GET)->defaultNull()->end() + ->scalarNode(Request::METHOD_HEAD)->defaultNull()->end() + ->scalarNode(Request::METHOD_POST)->defaultNull()->end() + ->scalarNode(Request::METHOD_DELETE)->defaultNull()->end() + ->scalarNode(Request::METHOD_PUT)->defaultNull()->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() // end of root/children + ->end(); // end of root - ->end() - ->end() // end of root/children - ->end() // end of root - ; - - return $treeBuilder; } } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/MissingBundleException.php b/src/Bundle/ChillMainBundle/DependencyInjection/MissingBundleException.php index 2b4f33b88..636cc69c3 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/MissingBundleException.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/MissingBundleException.php @@ -1,20 +1,25 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use LogicException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; -/** - * - * - * @author Julien Fastré - */ class RoleProvidersCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasDefinition('chill.main.role_provider')) { - throw new \LogicException('service chill.main.role_provider ' + throw new LogicException('service chill.main.role_provider ' . 'is not defined. It is required by RoleProviderCompilerPass'); } - + $definition = $container->getDefinition( 'chill.main.role_provider' ); @@ -44,14 +30,12 @@ class RoleProvidersCompilerPass implements CompilerPassInterface $taggedServices = $container->findTaggedServiceIds( 'chill.role' ); - + foreach ($taggedServices as $id => $tagAttributes) { $definition->addMethodCall( 'addProvider', - array(new Reference($id)) + [new Reference($id)] ); } - } - } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php index d26e09293..0b7bc2f2e 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AbstractWidgetsCompilerPass.php @@ -1,317 +1,233 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\Widget; +use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; +use Doctrine\Common\Proxy\Exception\InvalidArgumentException; +use LengthException; +use LogicException; +use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Doctrine\Common\Proxy\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Definition; -use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; -use Chill\MainBundle\DependencyInjection\Widget\HasWidgetFactoriesExtensionInterface; +use Symfony\Component\DependencyInjection\Reference; +use UnexpectedValueException; /** * Compile the configurations and inject required service into container. - * + * * The widgets are services tagged with : - * + * * ``` * { name: chill_widget, alias: my_alias, place: my_place } * ``` - * - * Or, if the tag does not exist or if you need to add some config to your + * + * Or, if the tag does not exist or if you need to add some config to your * service depending on the config, you should use a `WidgetFactory` (see * `WidgetFactoryInterface`. - * - * To reuse this compiler pass, simple execute the doProcess metho in your + * + * To reuse this compiler pass, simple execute the doProcess metho in your * compiler. Example : - * + * * ``` * namespace Chill\MainBundle\DependencyInjection\CompilerPass; - * + * * use Symfony\Component\DependencyInjection\ContainerBuilder; * use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass; * class WidgetsCompilerPass extends AbstractWidgetsCompilerPass { - * + * * public function process(ContainerBuilder $container) * { * $this->doProcess($container, 'chill_main', 'chill_main.widgets'); * } * } * ``` - * - * */ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface { - private $widgetServices = array(); - /** - * - * @var WidgetFactoryInterface[] + * the key to use to identify widget for a given place. */ - private $widgetFactories; - + public const WIDGET_CONFIG_ALIAS = 'widget_alias'; + /** - * The service which will manage the widgets - * + * the key to use to order widget for a given place. + */ + public const WIDGET_CONFIG_ORDER = 'order'; + + /** + * The service which will manage the widgets. + * * @var string */ - const WIDGET_MANAGER = 'chill.main.twig.widget'; - + public const WIDGET_MANAGER = 'chill.main.twig.widget'; + /** * the method wich register the widget into give service. */ - const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget'; - + public const WIDGET_MANAGER_METHOD_REGISTER = 'addWidget'; + /** - * the value of the `name` key in service definitions's tag - * - * @var string - */ - const WIDGET_SERVICE_TAG_NAME = 'chill_widget'; - - /** - * the key used to collect the alias in the service definition's tag. - * the alias must be + * the key used to collect the alias in the service definition's tag. + * the alias must be * injected into the configuration under 'alias' key. - * + * * @var string */ - const WIDGET_SERVICE_TAG_ALIAS = 'alias'; - + public const WIDGET_SERVICE_TAG_ALIAS = 'alias'; + /** - * the key used to collect the authorized place in the service definition's tag - * + * the value of the `name` key in service definitions's tag. + * * @var string */ - const WIDGET_SERVICE_TAG_PLACES = 'place'; - - /** - * the key to use to order widget for a given place - */ - const WIDGET_CONFIG_ORDER = 'order'; - - /** - * the key to use to identify widget for a given place - */ - const WIDGET_CONFIG_ALIAS = 'widget_alias'; - + public const WIDGET_SERVICE_TAG_NAME = 'chill_widget'; /** - * process the configuration and the container to add the widget available - * - * @param ContainerBuilder $container + * the key used to collect the authorized place in the service definition's tag. + * + * @var string + */ + public const WIDGET_SERVICE_TAG_PLACES = 'place'; + + /** + * cache of ordering by place. + * + * @internal used by function cacheAndGetOrdering + * + * @var array + */ + private $cacheOrdering = []; + + /** + * @var WidgetFactoryInterface[] + */ + private $widgetFactories; + + private $widgetServices = []; + + /** + * process the configuration and the container to add the widget available. + * * @param string $extension the extension of your bundle * @param string $containerWidgetConfigParameterName the key under which we can use the widget configuration - * @throws \LogicException - * @throws \UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface + * + * @throws LogicException + * @throws UnexpectedValueException if the given extension does not implement HasWidgetExtensionInterface * @throws \InvalidConfigurationException if there are errors in the config */ - public function doProcess(ContainerBuilder $container, $extension, - $containerWidgetConfigParameterName) - { + public function doProcess( + ContainerBuilder $container, + $extension, + $containerWidgetConfigParameterName + ) { if (!$container->hasDefinition(self::WIDGET_MANAGER)) { - throw new \LogicException("the service ".self::WIDGET_MANAGER." should". - " be present. It is required by ".self::class); + throw new LogicException('the service ' . self::WIDGET_MANAGER . ' should' . + ' be present. It is required by ' . self::class); } - + $managerDefinition = $container->getDefinition(self::WIDGET_MANAGER); - + // collect the widget factories /* @var $extensionClass HasWidgetFactoriesExtensionInterface */ $extensionClass = $container->getExtension($extension); // throw an error if extension does not implement HasWidgetFactoriesExtensionInterface if (!$extensionClass instanceof HasWidgetFactoriesExtensionInterface) { - throw new \UnexpectedValueException(sprintf("The extension for %s " - . "do not implements %s. You should implement %s on %s", - $extension, - HasWidgetFactoriesExtensionInterface::class, - HasWidgetFactoriesExtensionInterface::class, - get_class($extensionClass))); + throw new UnexpectedValueException(sprintf( + 'The extension for %s ' + . 'do not implements %s. You should implement %s on %s', + $extension, + HasWidgetFactoriesExtensionInterface::class, + HasWidgetFactoriesExtensionInterface::class, + get_class($extensionClass) + )); } - - + $this->widgetFactories = $extensionClass->getWidgetFactories(); - + // collect the availabled tagged services $this->collectTaggedServices($container); - + // collect the widgets and their config : $widgetParameters = $container->getParameter($containerWidgetConfigParameterName); - + // and add them to the delegated_block - foreach($widgetParameters as $place => $widgets) { - + foreach ($widgetParameters as $place => $widgets) { foreach ($widgets as $param) { $alias = $param[self::WIDGET_CONFIG_ALIAS]; // check that the service exists if (!array_key_exists($alias, $this->widgetServices)) { - throw new InvalidConfigurationException(sprintf("The alias %s". - " is not defined.", $alias)); + throw new InvalidConfigurationException(sprintf('The alias %s' . + ' is not defined.', $alias)); } - + // check that the widget is allowed at this place if (!$this->isPlaceAllowedForWidget($place, $alias, $container)) { throw new \InvalidConfigurationException(sprintf( - "The widget with alias %s is not allowed at place %s", - $alias, + 'The widget with alias %s is not allowed at place %s', + $alias, $place - )); + )); } - + // get the order, eventually corrected - $order = $this->cacheAndGetOrdering($place, $param[self::WIDGET_CONFIG_ORDER]); - + $order = $this->cacheAndGetOrdering($place, $param[self::WIDGET_CONFIG_ORDER]); + // register the widget with config to the service, using the method // `addWidget` if ($this->widgetServices[$alias] instanceof WidgetFactoryInterface) { /* @var $factory WidgetFactoryInterface */ $factory = $this->widgetServices[$alias]; // get the config (under the key which equals to widget_alias - $config = isset($param[$factory->getWidgetAlias()]) ? - $param[$factory->getWidgetAlias()] : array(); + $config = isset($param[$factory->getWidgetAlias()]) ? + $param[$factory->getWidgetAlias()] : []; // register the service into the container - $serviceId =$this->registerServiceIntoContainer($container, - $factory, $place, $order, $config); - - $managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER, - array( - $place, - $order, - new Reference($serviceId), - $config - )); + $serviceId = $this->registerServiceIntoContainer( + $container, + $factory, + $place, + $order, + $config + ); + + $managerDefinition->addMethodCall( + self::WIDGET_MANAGER_METHOD_REGISTER, + [ + $place, + $order, + new Reference($serviceId), + $config, + ] + ); } else { - $managerDefinition->addMethodCall(self::WIDGET_MANAGER_METHOD_REGISTER, - array( - $place, - $order, - new Reference($this->widgetServices[$alias]), - array() // the config is alway an empty array - )); + $managerDefinition->addMethodCall( + self::WIDGET_MANAGER_METHOD_REGISTER, + [ + $place, + $order, + new Reference($this->widgetServices[$alias]), + [], // the config is alway an empty array + ] + ); } } } } - - /** - * register the service into container. - * - * @param ContainerBuilder $container - * @param WidgetFactoryInterface $factory - * @param string $place - * @param float $order - * @param array $config - * @return string the id of the new service - */ - protected function registerServiceIntoContainer( - ContainerBuilder $container, - WidgetFactoryInterface $factory, - $place, - $order, - array $config - ) { - $serviceId = $factory->getServiceId($container, $place, $order, $config); - $definition = $factory->createDefinition($container, $place, - $order, $config); - $container->setDefinition($serviceId, $definition); - - return $serviceId; - } - - /** - * cache of ordering by place. - * - * @internal used by function cacheAndGetOrdering - * @var array - */ - private $cacheOrdering = array(); - - /** - * check if the ordering has already be used for the given $place and, - * if yes, correct the ordering by incrementation of 1 until the ordering - * has not be used. - * - * recursive method. - * - * @param string $place - * @param float $ordering - * @return float - */ - private function cacheAndGetOrdering($place, $ordering) { - // create a key in the cache array if not exists - if (!array_key_exists($place, $this->cacheOrdering)) { - $this->cacheOrdering[$place] = array(); - } - - // check if the order exists - if (array_search($ordering, $this->cacheOrdering[$place])) { - // if the order exists, increment of 1 and try again - return $this->cacheAndGetOrdering($place, $ordering + 1); - } else { - // cache the ordering - $this->cacheOrdering[$place][] = $ordering; - - return $ordering; - } - } - - /** - * get the places where the service is allowed - * - * @param Definition $definition - * @return unknown - */ - private function isPlaceAllowedForWidget($place, $widgetAlias, ContainerBuilder $container) - { - if ($this->widgetServices[$widgetAlias] instanceof WidgetFactoryInterface) { - if (in_array($place, $this->widgetServices[$widgetAlias] - ->getAllowedPlaces())) { - return true; - } - - } else { - $definition = $container->findDefinition($this->widgetServices[$widgetAlias]); - foreach($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) { - $placeValue = $attrs[self::WIDGET_SERVICE_TAG_PLACES]; - - if ($placeValue === $place) { - return true; - } - } - } - - return false; - } - /** * This method collect all service tagged with `self::WIDGET_SERVICE_TAG`, and - * add also the widget defined by factories - * + * add also the widget defined by factories. + * * This method also check that the service is correctly tagged with `alias` and * `places`, or the factory give a correct alias and more than one place. - * - * @param ContainerBuilder $container + * * @throws InvalidConfigurationException * @throws InvalidArgumentException */ @@ -320,69 +236,155 @@ abstract class AbstractWidgetsCompilerPass implements CompilerPassInterface // first, check the service tagged in service definition foreach ($container->findTaggedServiceIds(self::WIDGET_SERVICE_TAG_NAME) as $id => $attrs) { foreach ($attrs as $attr) { - // check the alias is set if (!isset($attr[self::WIDGET_SERVICE_TAG_ALIAS])) { - throw new InvalidConfigurationException("you should add an ".self::WIDGET_SERVICE_TAG_ALIAS. - " key on the service ".$id); + throw new InvalidConfigurationException('you should add an ' . self::WIDGET_SERVICE_TAG_ALIAS . + ' key on the service ' . $id); } - + // check the place is set if (!isset($attr[self::WIDGET_SERVICE_TAG_PLACES])) { throw new InvalidConfigurationException(sprintf( - "You should add a %s key on the service %s", + 'You should add a %s key on the service %s', self::WIDGET_SERVICE_TAG_PLACES, $id - )); + )); } - + // check the alias does not exists yet if (array_key_exists($attr[self::WIDGET_SERVICE_TAG_ALIAS], $this->widgetServices)) { - throw new InvalidArgumentException("a service has already be defined with the ". - self::WIDGET_SERVICE_TAG_ALIAS." ".$attr[self::WIDGET_SERVICE_TAG_ALIAS]); + throw new InvalidArgumentException('a service has already be defined with the ' . + self::WIDGET_SERVICE_TAG_ALIAS . ' ' . $attr[self::WIDGET_SERVICE_TAG_ALIAS]); } - + // register the service as available $this->widgetServices[$attr[self::WIDGET_SERVICE_TAG_ALIAS]] = $id; } } - + // add the services defined by factories - foreach($this->widgetFactories as $factory) { + foreach ($this->widgetFactories as $factory) { /* @var $factory WidgetFactoryInterface */ $alias = $factory->getWidgetAlias(); - + // check the alias is not empty if (empty($alias)) { - throw new \LogicException(sprintf( - "the widget factory %s returns an empty alias", - get_class($factory))); + throw new LogicException(sprintf( + 'the widget factory %s returns an empty alias', + get_class($factory) + )); } - + // check the places are not empty if (!is_array($factory->getAllowedPlaces())) { - throw new \UnexpectedValueException("the method 'getAllowedPlaces' " - . "should return a non-empty array. Unexpected value on ". + throw new UnexpectedValueException("the method 'getAllowedPlaces' " + . 'should return a non-empty array. Unexpected value on ' . get_class($factory)); } - + if (count($factory->getAllowedPlaces()) == 0) { - throw new \LengthException("The method 'getAllowedPlaces' should " - . "return a non-empty array, but returned 0 elements on ". - get_class($factory).'::getAllowedPlaces()'); + throw new LengthException("The method 'getAllowedPlaces' should " + . 'return a non-empty array, but returned 0 elements on ' . + get_class($factory) . '::getAllowedPlaces()'); } - + // check the alias does not exists yet if (array_key_exists($alias, $this->widgetServices)) { - throw new InvalidArgumentException("a service has already be defined with the ". - self::WIDGET_SERVICE_TAG_ALIAS." ".$alias); + throw new InvalidArgumentException('a service has already be defined with the ' . + self::WIDGET_SERVICE_TAG_ALIAS . ' ' . $alias); } - + // register the factory as available $this->widgetServices[$factory->getWidgetAlias()] = $factory; - } } - - -} \ No newline at end of file + + /** + * register the service into container. + * + * @param string $place + * @param float $order + * + * @return string the id of the new service + */ + protected function registerServiceIntoContainer( + ContainerBuilder $container, + WidgetFactoryInterface $factory, + $place, + $order, + array $config + ) { + $serviceId = $factory->getServiceId($container, $place, $order, $config); + $definition = $factory->createDefinition( + $container, + $place, + $order, + $config + ); + $container->setDefinition($serviceId, $definition); + + return $serviceId; + } + + /** + * check if the ordering has already be used for the given $place and, + * if yes, correct the ordering by incrementation of 1 until the ordering + * has not be used. + * + * recursive method. + * + * @param string $place + * @param float $ordering + * + * @return float + */ + private function cacheAndGetOrdering($place, $ordering) + { + // create a key in the cache array if not exists + if (!array_key_exists($place, $this->cacheOrdering)) { + $this->cacheOrdering[$place] = []; + } + + // check if the order exists + if (array_search($ordering, $this->cacheOrdering[$place])) { + // if the order exists, increment of 1 and try again + return $this->cacheAndGetOrdering($place, $ordering + 1); + } + // cache the ordering + $this->cacheOrdering[$place][] = $ordering; + + return $ordering; + } + + /** + * get the places where the service is allowed. + * + * @param mixed $place + * @param mixed $widgetAlias + * + * @return unknown + */ + private function isPlaceAllowedForWidget($place, $widgetAlias, ContainerBuilder $container) + { + if ($this->widgetServices[$widgetAlias] instanceof WidgetFactoryInterface) { + if ( + in_array($place, $this->widgetServices[$widgetAlias] + ->getAllowedPlaces()) + ) { + return true; + } + } else { + $definition = $container->findDefinition($this->widgetServices[$widgetAlias]); + + foreach ($definition->getTag(self::WIDGET_SERVICE_TAG_NAME) as $attrs) { + $placeValue = $attrs[self::WIDGET_SERVICE_TAG_PLACES]; + + if ($placeValue === $place) { + return true; + } + } + } + + return false; + } +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AddWidgetConfigurationTrait.php b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AddWidgetConfigurationTrait.php index 847af0618..8e377880f 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AddWidgetConfigurationTrait.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/AddWidgetConfigurationTrait.php @@ -1,90 +1,81 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\Widget; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Chill\MainBundle\DependencyInjection\Widget\AbstractWidgetsCompilerPass as WidgetsCompilerPass; +use Generator; +use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; - +use Symfony\Component\DependencyInjection\ContainerBuilder; +use function implode; /** * This trait allow to add automatic configuration for widget inside your config. - * - * Usage + * + * Usage * ====== - * + * * 1. Register widget factories * ---------------------------- - * + * * Add widget factories, using `setWidgetFactories` - * - * Example : - * + * + * Example : + * * ``` * use Symfony\Component\DependencyInjection\ContainerBuilder; * use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait; - * - * class MyConfig + * + * class MyConfig * { - * + * * use addWidgetConfigurationTrait; - * + * * public function __construct(array $widgetFactories = array(), ContainerBuilder $container) * { * $this->setWidgetFactories($widgetFactories); * // will be used on next step * $this->container = $container; * } - * + * * } * ``` - * - * - * + * + * + * * 2. add widget config to your config * ----------------------------------- - * + * * ``` * use Symfony\Component\DependencyInjection\ContainerBuilder; * use Chill\MainBundle\DependencyInjection\Widget\AddWidgetConfigurationTrait; * use Symfony\Component\Config\Definition\Builder\TreeBuilder; - * - * class MyConfig + * + * class MyConfig * { - * + * * use addWidgetConfigurationTrait; - * + * * private $container; - * + * * public function __construct(array $widgetFactories = array(), ContainerBuilder $container) * { * $this->setWidgetFactories($widgetFactories); * $this->container; * } - * + * * public function getConfigTreeBuilder() * { * $treeBuilder = new TreeBuilder(); * $root = $treeBuilder->root('my_root'); - * + * * $root->children() * ->arrayNode('widgets') * ->canBeDisabled() @@ -93,15 +84,15 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; * ->end() * ->end() * ; - * + * * return $treeBuilder; * } - * + * * } * ``` - * - * the above code will add to the config : - * + * + * the above code will add to the config : + * * ``` * widgets: * enabled: true @@ -113,8 +104,6 @@ use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; * person_list: * # options for the person_list * ``` - * - * */ trait AddWidgetConfigurationTrait { @@ -122,16 +111,7 @@ trait AddWidgetConfigurationTrait * @param WidgetFactoryInterface[] */ private $widgetFactories; - - /** - * - * @param WidgetFactoryInterface[] $widgetFactories - */ - public function setWidgetFactories(array $widgetFactories) - { - $this->widgetFactories = $widgetFactories; - } - + /** * @return WidgetFactoryInterface[] */ @@ -139,12 +119,20 @@ trait AddWidgetConfigurationTrait { return $this->widgetFactories; } - + + /** + * @param WidgetFactoryInterface[] $widgetFactories + */ + public function setWidgetFactories(array $widgetFactories) + { + $this->widgetFactories = $widgetFactories; + } + /** * add configuration nodes for the widget at the given place. - * + * * @param type $place - * @param ContainerBuilder $containerBuilder + * * @return type */ protected function addWidgetsConfiguration($place, ContainerBuilder $containerBuilder) @@ -152,101 +140,104 @@ trait AddWidgetConfigurationTrait $treeBuilder = new TreeBuilder($place); $root = $treeBuilder->getRootNode($place) ->canBeUnset() - ->info('register widgets on place "'.$place.'"'); - + ->info('register widgets on place "' . $place . '"'); + // if no childen, return the root if (count(iterator_to_array($this->filterWidgetByPlace($place))) === 0) { return $root; } - + $prototypeChildren = $root->prototype('array')->children(); - + $prototypeChildren ->floatNode(WidgetsCompilerPass::WIDGET_CONFIG_ORDER) - ->isRequired() - ->info("the ordering of the widget. May be a number with decimal") - ->example("10.58") - ->end() + ->isRequired() + ->info('the ordering of the widget. May be a number with decimal') + ->example('10.58') + ->end() ->scalarNode(WidgetsCompilerPass::WIDGET_CONFIG_ALIAS) // this node is scalar: when the configuration is build, the // tagged services are not available. But when the config reference // is build, the services are avaialble => we add the possible aliases // in the info. - ->info("the widget alias (see your installed bundles config). " - . "Possible values are (maybe incomplete) : ". - \implode(", ", $this->getWidgetAliasesbyPlace($place, $containerBuilder))) - ->isRequired() - ->end() - ; - + ->info('the widget alias (see your installed bundles config). ' + . 'Possible values are (maybe incomplete) : ' . + implode(', ', $this->getWidgetAliasesbyPlace($place, $containerBuilder))) + ->isRequired() + ->end(); + // adding the possible config on each widget under the widget_alias foreach ($this->filterWidgetByPlace($place) as $factory) { $builder = new TreeBuilder($factory->getWidgetAlias()); $widgetOptionsRoot = $builder->getRootNode($factory->getWidgetAlias()); $widgetOptionsRoot->canBeUnset() - ->info(sprintf('the configuration for the widget "%s" (only required if this widget is set in widget_alias)', - $factory->getWidgetAlias())); + ->info(sprintf( + 'the configuration for the widget "%s" (only required if this widget is set in widget_alias)', + $factory->getWidgetAlias() + )); $factory->configureOptions($place, $widgetOptionsRoot->children()); $prototypeChildren->append($widgetOptionsRoot); } - + return $root; } - + /** * get all widget factories for the given place. * * @param string $place - * @return \Generator a generator containing a widget factory + * + * @return Generator a generator containing a widget factory */ protected function filterWidgetByPlace($place) { - foreach($this->widgetFactories as $factory) { + foreach ($this->widgetFactories as $factory) { if (in_array($place, $factory->getAllowedPlaces())) { yield $factory; } } } - + /** * get the all possible aliases for the given place. This method - * search within service tags and widget factories - * - * **Note** that services are not available when the config is build: the whole + * search within service tags and widget factories. + * + * **Note** that services are not available when the config is build: the whole * aliases will be checked in compiler pass, or when the command * `config:dump-reference` is runned. - * + * * @param type $place - * @param ContainerBuilder $containerBuilder - * @return type + * * @throws InvalidConfigurationException if a service's tag does not have the "alias" key + * + * @return type */ protected function getWidgetAliasesbyPlace($place, ContainerBuilder $containerBuilder) { - $result = array(); - + $result = []; + foreach ($this->filterWidgetByPlace($place) as $factory) { $result[] = $factory->getWidgetAlias(); } // append the aliases added without factory foreach ($containerBuilder - ->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME) + ->findTaggedServiceIds(WidgetsCompilerPass::WIDGET_SERVICE_TAG_NAME) as $serviceId => $tags) { - foreach ($tags as $tag) { - // throw an error if no alias in definition - if (!array_key_exists(WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS, $tag)) { - throw new InvalidConfigurationException(sprintf( - "The service with id %s does not have any %d key", - $serviceId, - WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS - )); - } - // add the key to the possible results - $result[] = $tag[WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS]; + foreach ($tags as $tag) { + // throw an error if no alias in definition + if (!array_key_exists(WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS, $tag)) { + throw new InvalidConfigurationException(sprintf( + 'The service with id %s does not have any %d key', + $serviceId, + WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS + )); } + // add the key to the possible results + $result[] = $tag[WidgetsCompilerPass::WIDGET_SERVICE_TAG_ALIAS]; } - + } + return $result; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/AbstractWidgetFactory.php b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/AbstractWidgetFactory.php index 7e5a12871..e6153bc4e 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/AbstractWidgetFactory.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/AbstractWidgetFactory.php @@ -1,47 +1,32 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\Widget\Factory; -use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; /** - * Allow to easily create WidgetFactory. - * + * Allow to easily create WidgetFactory. + * * Extending this factory, the widget will be created using the already defined * service created "as other services" in your configuration (the most frequent * way is using `services.yml` file. - * - * If you need to create different service based upon place, position or + * + * If you need to create different service based upon place, position or * definition, you should implements directly * `Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface` - * - * */ abstract class AbstractWidgetFactory implements WidgetFactoryInterface { - /** - * * {@inheritdoc} - * + * * Will create the definition by returning the definition from the `services.yml` * file (or `services.xml` or `what-you-want.yml`). * @@ -49,9 +34,9 @@ abstract class AbstractWidgetFactory implements WidgetFactoryInterface */ public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config) { - return $containerBuilder->getDefinition($this + return $containerBuilder->getDefinition( + $this ->getServiceId($containerBuilder, $place, $order, $config) - ); + ); } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/WidgetFactoryInterface.php b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/WidgetFactoryInterface.php index 6e7836b01..99092e461 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/WidgetFactoryInterface.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/Factory/WidgetFactoryInterface.php @@ -1,52 +1,41 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\Widget\Factory; - use Symfony\Component\Config\Definition\Builder\NodeBuilder; use Symfony\Component\DependencyInjection\ContainerBuilder; /** * Factory for creating configuration of widgets. - * + * * When you need a widget with some configuration, you should implements this - * interface on a factory. The factory will add configuration to the bundle + * interface on a factory. The factory will add configuration to the bundle * giving the places for your widget. - * - * Using this interface, **you do not need** to define the service in your - * container configuration (`services.yml` files). - * + * + * Using this interface, **you do not need** to define the service in your + * container configuration (`services.yml` files). + * * Once the class is created, you should inject the factory inside the container * at compile time, in your `Bundle` class : - * - * + * + * * ``` * namespace Chill\PersonBundle; * * use Symfony\Component\HttpKernel\Bundle\Bundle; * use Symfony\Component\DependencyInjection\ContainerBuilder; * use Chill\PersonBundle\Widget\PersonListWidgetFactory; - * + * * class ChillPersonBundle extends Bundle * { - * public function build(ContainerBuilder $container) + * public function build(ContainerBuilder $container) * { * parent::build($container); * // register a widget factory into chill_main : @@ -55,49 +44,40 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; * } * } * ``` - * - * - * */ interface WidgetFactoryInterface { /** - * configure options for the widget. Those options will be added in + * configure options for the widget. Those options will be added in * configuration in the bundle where the widget will be used. - * + * * @param type $place - * @param NodeBuilder $node */ public function configureOptions($place, NodeBuilder $node); - - /** - * get the widget alias. This alias will be used in configuration (`config.yml`) - */ - public function getWidgetAlias(); - + /** * Create a definition for the service which will render the widget. - * - * (Note: you can define the service by yourself, as other services, + * + * (Note: you can define the service by yourself, as other services, * using the `AbstractWidgetFactory`) - * - * @param ContainerBuilder $containerBuilder + * * @param type $place * @param type $order - * @param array $config */ public function createDefinition(ContainerBuilder $containerBuilder, $place, $order, array $config); - + /** * return the service id to build the widget. - * - * @param ContainerBuilder $containerBuilder + * * @param string $place * @param float $order - * @param array $config - * + * * @return string the service definition - * */ public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config); + + /** + * get the widget alias. This alias will be used in configuration (`config.yml`). + */ + public function getWidgetAlias(); } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/HasWidgetFactoriesExtensionInterface.php b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/HasWidgetFactoriesExtensionInterface.php index b25c487b6..702ba15da 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Widget/HasWidgetFactoriesExtensionInterface.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Widget/HasWidgetFactoriesExtensionInterface.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\DependencyInjection\Widget; @@ -23,20 +13,19 @@ use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface; /** * Register widget factories to an extension. - * */ -interface HasWidgetFactoriesExtensionInterface { - +interface HasWidgetFactoriesExtensionInterface +{ /** - * register a widget factory - * + * register a widget factory. + * * @param \Chill\MainBundle\DependencyInjection\Widget\WidgetFactoryInterface $factory */ public function addWidgetFactory(WidgetFactoryInterface $factory); - + /** - * get all the widget factories registered for this extension - * + * get all the widget factories registered for this extension. + * * @return WidgetFactoryInterface[] */ public function getWidgetFactories(); diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/GetJsonFieldByKey.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/GetJsonFieldByKey.php index addc6b9b7..0a60974b1 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/GetJsonFieldByKey.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/GetJsonFieldByKey.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; @@ -22,16 +14,21 @@ use Doctrine\ORM\Query\Lexer; use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; -/** - * - * - * @author Julien Fastré - */ class GetJsonFieldByKey extends FunctionNode { private $expr1; + private $expr2; + public function getSql(SqlWalker $sqlWalker) + { + return sprintf( + '(%s->%s)', + $this->expr1->dispatch($sqlWalker), + $this->expr2->dispatch($sqlWalker) + ); + } + public function parse(Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); @@ -41,13 +38,4 @@ class GetJsonFieldByKey extends FunctionNode $this->expr2 = $parser->StringPrimary(); $parser->match(Lexer::T_CLOSE_PARENTHESIS); } - - public function getSql(SqlWalker $sqlWalker) - { - return sprintf( - '(%s->%s)', - $this->expr1->dispatch($sqlWalker), - $this->expr2->dispatch($sqlWalker) - ); - } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonAggregate.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonAggregate.php index 54ef45493..a2d2b1f82 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonAggregate.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonAggregate.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; @@ -24,16 +16,14 @@ use Doctrine\ORM\Query\SqlWalker; /** * Return an aggregation of values in a json representation, as a string. - * + * * Internally, this function use the postgresql `jsonb_agg` function. Using * json allow to aggregate data from different types without have to cast them. - * - * @author Julien Fastré */ class JsonAggregate extends FunctionNode { private $expr; - + public function getSql(SqlWalker $sqlWalker) { return sprintf('jsonb_agg(%s)', $this->expr->dispatch($sqlWalker)); diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbExistsInArray.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbExistsInArray.php index 6c4eaa5c3..fddc72c29 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbExistsInArray.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/JsonbExistsInArray.php @@ -1,8 +1,12 @@ - */ class JsonbExistsInArray extends FunctionNode { private $expr1; + private $expr2; - + public function getSql(SqlWalker $sqlWalker): string { return sprintf( diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php index ae9df72f4..0ce6c510c 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/OverlapsI.php @@ -1,110 +1,102 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; /** - * DQL function for OVERLAPS function in postgresql - * - * If a value is null in period start, it will be replaced by -infinity. + * DQL function for OVERLAPS function in postgresql. + * + * If a value is null in period start, it will be replaced by -infinity. * If a value is null in period end, it will be replaced by infinity - * */ class OverlapsI extends FunctionNode { - private $firstPeriodStart; - private $firstPeriodEnd; - - private $secondPeriodStart; - + + private $firstPeriodStart; + private $secondPeriodEnd; - + + private $secondPeriodStart; + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { return '(' - .$this->makeCase($sqlWalker, $this->firstPeriodStart, 'start').', ' - .$this->makeCase($sqlWalker, $this->firstPeriodEnd, 'end'). + . $this->makeCase($sqlWalker, $this->firstPeriodStart, 'start') . ', ' + . $this->makeCase($sqlWalker, $this->firstPeriodEnd, 'end') . ') OVERLAPS (' - .$this->makeCase($sqlWalker, $this->secondPeriodStart, 'start').', ' - .$this->makeCase($sqlWalker, $this->secondPeriodEnd, 'end').')' - ; - } - - protected function makeCase($sqlWalker, $part, $position) - { - //return $part->dispatch($sqlWalker); - - switch ($position) { - case 'start' : - $p = '-infinity'; - break; - case 'end': - $p = 'infinity'; - break; - } - - if ($part instanceof \Doctrine\ORM\Query\AST\PathExpression) { - return 'CASE WHEN ' - .' '.$part->dispatch($sqlWalker).' IS NOT NULL ' - . 'THEN '. - $part->dispatch($sqlWalker) - . ' ELSE '. - "'".$p."'::date " - . 'END'; - } else { - return 'CASE WHEN ' - .' '.$part->dispatch($sqlWalker).'::date IS NOT NULL ' - . 'THEN '. - $part->dispatch($sqlWalker) - . '::date ELSE '. - "'".$p."'::date " - . 'END'; - } + . $this->makeCase($sqlWalker, $this->secondPeriodStart, 'start') . ', ' + . $this->makeCase($sqlWalker, $this->secondPeriodEnd, 'end') . ')'; } public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); - + $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->firstPeriodStart = $parser->StringPrimary(); - + $parser->match(Lexer::T_COMMA); - + $this->firstPeriodEnd = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); - + $parser->match(Lexer::T_COMMA); - + $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->secondPeriodStart = $parser->StringPrimary(); - + $parser->match(Lexer::T_COMMA); - + $this->secondPeriodEnd = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } + + protected function makeCase($sqlWalker, $part, $position) + { + //return $part->dispatch($sqlWalker); + + switch ($position) { + case 'start': + $p = '-infinity'; + + break; + + case 'end': + $p = 'infinity'; + + break; + } + + if ($part instanceof \Doctrine\ORM\Query\AST\PathExpression) { + return 'CASE WHEN ' + . ' ' . $part->dispatch($sqlWalker) . ' IS NOT NULL ' + . 'THEN ' . + $part->dispatch($sqlWalker) + . ' ELSE ' . + "'" . $p . "'::date " + . 'END'; + } + + return 'CASE WHEN ' + . ' ' . $part->dispatch($sqlWalker) . '::date IS NOT NULL ' + . 'THEN ' . + $part->dispatch($sqlWalker) + . '::date ELSE ' . + "'" . $p . "'::date " + . 'END'; + } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Replace.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Replace.php index 6d30ec7d9..779d1281d 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/Replace.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Replace.php @@ -1,46 +1,33 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; -/** - * - * - */ class Replace extends FunctionNode { - protected $string; - protected $from; - + + protected $string; + protected $to; - + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker): string { - return 'REPLACE('. - $this->string->dispatch($sqlWalker). - ', '. - $this->from->dispatch($sqlWalker). - ', '. - $this->to->dispatch($sqlWalker). + return 'REPLACE(' . + $this->string->dispatch($sqlWalker) . + ', ' . + $this->from->dispatch($sqlWalker) . + ', ' . + $this->to->dispatch($sqlWalker) . ')'; } @@ -48,17 +35,17 @@ class Replace extends FunctionNode { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->string = $parser->StringPrimary(); - + $parser->match(Lexer::T_COMMA); - + $this->from = $parser->StringPrimary(); - + $parser->match(Lexer::T_COMMA); - + $this->to = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php index 988e55f5f..0ef7d8b2f 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Similarity.php @@ -1,54 +1,40 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; -/** - * - * - * - */ class Similarity extends FunctionNode { private $firstPart; - + private $secondPart; - + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { - return 'SIMILARITY('.$this->firstPart->dispatch($sqlWalker). - ', ' . $this->secondPart->dispatch($sqlWalker) .")"; + return 'SIMILARITY(' . $this->firstPart->dispatch($sqlWalker) . + ', ' . $this->secondPart->dispatch($sqlWalker) . ')'; } public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->firstPart = $parser->StringPrimary(); - + $parser->match(Lexer::T_COMMA); - + $this->secondPart = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/DQL/Unaccent.php b/src/Bundle/ChillMainBundle/Doctrine/DQL/Unaccent.php index 2ced15344..80e3e58e8 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/DQL/Unaccent.php +++ b/src/Bundle/ChillMainBundle/Doctrine/DQL/Unaccent.php @@ -1,21 +1,10 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Doctrine\DQL; @@ -24,30 +13,27 @@ use Doctrine\ORM\Query\AST\Functions\FunctionNode; use Doctrine\ORM\Query\Lexer; /** - * Unaccent string using postgresql extension unaccent : - * http://www.postgresql.org/docs/current/static/unaccent.html - * - * Usage : StringFunction UNACCENT(string) + * Unaccent string using postgresql extension unaccent : + * http://www.postgresql.org/docs/current/static/unaccent.html. * - * @author Julien Fastré + * Usage : StringFunction UNACCENT(string) */ class Unaccent extends FunctionNode { private $string; - + public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) { - return 'UNACCENT(' . $this->string->dispatch($sqlWalker) .")"; + return 'UNACCENT(' . $this->string->dispatch($sqlWalker) . ')'; } public function parse(\Doctrine\ORM\Query\Parser $parser) { $parser->match(Lexer::T_IDENTIFIER); $parser->match(Lexer::T_OPEN_PARENTHESIS); - + $this->string = $parser->StringPrimary(); - + $parser->match(Lexer::T_CLOSE_PARENTHESIS); } - } diff --git a/src/Bundle/ChillMainBundle/Doctrine/Migrations/VersionComparator.php b/src/Bundle/ChillMainBundle/Doctrine/Migrations/VersionComparator.php index 120d621a0..f1e528213 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Migrations/VersionComparator.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Migrations/VersionComparator.php @@ -1,12 +1,19 @@ getNumber($a), $this->getNumber($b)); + } + private function getNumber(Version $version): string { - $names = explode("\\", (string) $version); + $names = explode('\\', (string) $version); return end($names); } - - public function compare(Version $a, Version $b): int - { - $q = strcmp($this->getNumber($a), $this->getNumber($b)); - - return $q; - } } - diff --git a/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php b/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php index 43c21ae59..bb22262fa 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Model/Point.php @@ -1,66 +1,57 @@ lat = $lat; $this->lon = $lon; } - public function toGeoJson(): string + public static function fromArrayGeoJson(array $array): Point { - $array = $this->toArrayGeoJson(); - return \json_encode($array); - } - - public function jsonSerialize(): array - { - return $this->toArrayGeoJson(); - } - - public function toArrayGeoJson(): array - { - return [ - "type" => "Point", - "coordinates" => [ $this->lon, $this->lat ] - ]; + if ( + 'Point' == $array['type'] + && isset($array['coordinates']) + ) { + return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]); + } } /** - * - * @return string - */ - public function toWKT(): string - { - return 'SRID='.self::$SRID.';POINT('.$this->lon.' '.$this->lat.')'; - } - - /** - * * @param type $geojson - * @return Point */ public static function fromGeoJson(string $geojson): Point { $a = json_decode($geojson); //check if the geojson string is correct - if (NULL === $a or !isset($a->type) or !isset($a->coordinates)){ + if (null === $a or !isset($a->type) or !isset($a->coordinates)) { throw PointException::badJsonString($geojson); } - if ($a->type != 'Point'){ + if ('Point' != $a->type) { throw PointException::badGeoType(); } @@ -72,21 +63,11 @@ class Point implements JsonSerializable { public static function fromLonLat(float $lon, float $lat): Point { - if (($lon > -180 && $lon < 180) && ($lat > -90 && $lat < 90)) - { + if ((-180 < $lon && 180 > $lon) && (-90 < $lat && 90 > $lat)) { return new Point($lon, $lat); - } else { - throw PointException::badCoordinates($lon, $lat); } - } - public static function fromArrayGeoJson(array $array): Point - { - if ($array['type'] == 'Point' && - isset($array['coordinates'])) - { - return self::fromLonLat($array['coordinates'][0], $array['coordinates'][1]); - } + throw PointException::badCoordinates($lon, $lat); } public function getLat(): float @@ -98,6 +79,29 @@ class Point implements JsonSerializable { { return $this->lon; } + + public function jsonSerialize(): array + { + return $this->toArrayGeoJson(); + } + + public function toArrayGeoJson(): array + { + return [ + 'type' => 'Point', + 'coordinates' => [$this->lon, $this->lat], + ]; + } + + public function toGeoJson(): string + { + $array = $this->toArrayGeoJson(); + + return json_encode($array); + } + + public function toWKT(): string + { + return 'SRID=' . self::$SRID . ';POINT(' . $this->lon . ' ' . $this->lat . ')'; + } } - - diff --git a/src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php b/src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php index 4e3101435..98a8b0e9d 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Model/PointException.php @@ -1,27 +1,33 @@ + * postgreql. */ class NativeDateIntervalType extends DateIntervalType { - const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS'; - + public const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS'; + + public function convertToDatabaseValue($value, AbstractPlatform $platform) + { + if (null === $value) { + return null; + } + + if ($value instanceof DateInterval) { + return $value->format(self::FORMAT); + } + + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); + } + + public function convertToPHPValue($value, AbstractPlatform $platform) + { + if (null === $value || $value instanceof DateInterval) { + return $value; + } + + try { + $strings = explode(' ', $value); + + if (count($strings) === 0) { + return null; + } + $intervalSpec = 'P'; + reset($strings); + + do { + $intervalSpec .= $this->convertEntry($strings); + } while (next($strings) !== false); + + return new DateInterval($intervalSpec); + } catch (Exception $exception) { + throw $this->createConversionException($value, $exception); + } + } + public function getName(): string { return \Doctrine\DBAL\Types\Type::DATEINTERVAL; @@ -25,87 +74,53 @@ class NativeDateIntervalType extends DateIntervalType { return 'INTERVAL'; } - - /** - * {@inheritdoc} - */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) - { - if (null === $value) { - return null; - } - if ($value instanceof \DateInterval) { - return $value->format(self::FORMAT); - } - - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateInterval']); - } - - public function convertToPHPValue($value, AbstractPlatform $platform) - { - if ($value === null || $value instanceof \DateInterval) { - return $value; - } - - try { - $strings = explode(' ', $value); - - if (count($strings) === 0) { - return null; - } - $intervalSpec = 'P'; - \reset($strings); - - do { - $intervalSpec .= $this->convertEntry($strings); - } while (next($strings) !== FALSE); - - return new \DateInterval($intervalSpec); - } catch (\Exception $exception) { - throw $this->createConversionException($value, $exception); - } - } - - private function convertEntry(&$strings) - { - $current = \current($strings); - - if (is_numeric($current)) { - $next = \next($strings); - switch($next) { - case 'year': - case 'years': - $unit = 'Y'; - break; - case 'mon': - case 'mons': - $unit = 'M'; - break; - case 'day': - case 'days': - $unit = 'D'; - break; - default: - throw $this->createConversionException(implode('', $strings)); - } - - return $current.$unit; - - } elseif (\preg_match('/([0-9]{2}\:[0-9]{2}:[0-9]{2})/', $current) === 1) { - $tExploded = explode(':', $current); - $intervalSpec = 'T'; - $intervalSpec.= $tExploded[0].'H'; - $intervalSpec.= $tExploded[1].'M'; - $intervalSpec.= $tExploded[2].'S'; - - return $intervalSpec; - } - } - protected function createConversionException($value, $exception = null) { return ConversionException::conversionFailedFormat($value, $this->getName(), 'xx year xx mons xx days 01:02:03', $exception); } + private function convertEntry(&$strings) + { + $current = current($strings); + + if (is_numeric($current)) { + $next = \next($strings); + + switch ($next) { + case 'year': + case 'years': + $unit = 'Y'; + + break; + + case 'mon': + case 'mons': + $unit = 'M'; + + break; + + case 'day': + case 'days': + $unit = 'D'; + + break; + + default: + throw $this->createConversionException(implode('', $strings)); + } + + return $current . $unit; + } + + if (preg_match('/([0-9]{2}\:[0-9]{2}:[0-9]{2})/', $current) === 1) { + $tExploded = explode(':', $current); + $intervalSpec = 'T'; + $intervalSpec .= $tExploded[0] . 'H'; + $intervalSpec .= $tExploded[1] . 'M'; + $intervalSpec .= $tExploded[2] . 'S'; + + return $intervalSpec; + } + } } diff --git a/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php b/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php index 086b566da..bf5746acb 100644 --- a/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php +++ b/src/Bundle/ChillMainBundle/Doctrine/Type/PointType.php @@ -1,46 +1,62 @@ toWKT(); + } + + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return $sqlExpr; } /** - * * @param type $value - * @param AbstractPlatform $platform + * * @return Point */ public function convertToPHPValue($value, AbstractPlatform $platform) { - if ($value === NULL){ - return NULL; - } else { - return Point::fromGeoJson($value); + if (null === $value) { + return null; } + + return Point::fromGeoJson($value); + } + + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return 'ST_AsGeoJSON(' . $sqlExpr . ') '; } public function getName() @@ -48,28 +64,11 @@ class PointType extends Type { return self::POINT; } - public function convertToDatabaseValue($value, AbstractPlatform $platform) + /** + * @return type + */ + public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform) { - if ($value === NULL){ - return NULL; - } else { - return $value->toWKT(); - } - } - - public function canRequireSQLConversion() - { - return true; - } - - public function convertToPHPValueSQL($sqlExpr, $platform) - { - return 'ST_AsGeoJSON('.$sqlExpr.') '; - } - - public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) - { - return $sqlExpr; + return 'geometry(POINT,' . Point::$SRID . ')'; } } - diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php index 36eda09c2..88d1ebb8b 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -1,72 +1,30 @@ validFrom = new \DateTime(); + $this->validFrom = new DateTime(); + } + + public static function createFromAddress(Address $original): Address + { + return (new Address()) + ->setPostcode($original->getPostcode()) + ->setStreetAddress1($original->getStreetAddress1()) + ->setStreetAddress2($original->getStreetAddress2()) + ->setValidFrom($original->getValidFrom()); + } + + public function getBuildingName(): ?string + { + return $this->buildingName; + } + + public function getCorridor(): ?string + { + return $this->corridor; } /** - * Get id + * Get customs informations in the address. + */ + public function getCustoms(): array + { + return $this->customs; + } + + public function getDistribution(): ?string + { + return $this->distribution; + } + + public function getExtra(): ?string + { + return $this->extra; + } + + public function getFlat(): ?string + { + return $this->flat; + } + + public function getFloor(): ?string + { + return $this->floor; + } + + /** + * Get id. * - * @return integer + * @return int */ public function getId() { @@ -164,21 +220,47 @@ class Address } /** - * Set streetAddress1 (legacy function) + * Get IsNoAddress. * - * @param string $streetAddress1 - * - * @return Address + * Indicate true if the address is a fake address (homeless, ...) */ - public function setStreetAddress1($streetAddress1) + public function getIsNoAddress(): bool { - $this->street = $streetAddress1 === NULL ? '' : $streetAddress1; + return $this->isNoAddress; + } - return $this; + public function getLinkedToThirdParty() + { + return $this->linkedToThirdParty; + } + + public function getPoint(): ?Point + { + return $this->point; } /** - * Get streetAddress1 (legacy function) + * Get postcode. + * + * @return PostalCode + */ + public function getPostcode() + { + return $this->postcode; + } + + public function getSteps(): ?string + { + return $this->steps; + } + + public function getStreet(): ?string + { + return $this->street; + } + + /** + * Get streetAddress1 (legacy function). * * @return string */ @@ -188,21 +270,7 @@ class Address } /** - * Set streetAddress2 (legacy function) - * - * @param string $streetAddress2 - * - * @return Address - */ - public function setStreetAddress2($streetAddress2) - { - $this->streetNumber = $streetAddress2 === NULL ? '' : $streetAddress2; - - return $this; - } - - /** - * Get streetAddress2 (legacy function) + * Get streetAddress2 (legacy function). * * @return string */ @@ -211,96 +279,46 @@ class Address return $this->streetNumber; } - /** - * Set postcode - * - * @param PostalCode $postcode - * - * @return Address - */ - public function setPostcode(PostalCode $postcode = null) + public function getStreetNumber(): ?string { - $this->postcode = $postcode; - - return $this; + return $this->streetNumber; } /** - * Get postcode - * - * @return PostalCode - */ - public function getPostcode() - { - return $this->postcode; - } - - /** - * @return \DateTime + * @return DateTime */ public function getValidFrom() { return $this->validFrom; } - /** - * @param \DateTime $validFrom - * @return Address - */ - public function setValidFrom(\DateTime $validFrom) + public function getValidTo(): ?DateTimeInterface { - $this->validFrom = $validFrom; - return $this; + return $this->validTo; } - /** - * Get IsNoAddress - * - * Indicate true if the address is a fake address (homeless, ...) - * - * @return bool - */ - public function getIsNoAddress(): bool - { - return $this->isNoAddress; - } - - /** - * @return bool - */ public function isNoAddress(): bool { return $this->getIsNoAddress(); } - /** - * Set IsNoAddress - * - * Indicate true if the address is a fake address (homeless, ...) - * - * @param bool $isNoAddress - * @return $this - */ - public function setIsNoAddress(bool $isNoAddress) + public function setBuildingName(?string $buildingName): self { - $this->isNoAddress = $isNoAddress; + $this->buildingName = $buildingName; + + return $this; + } + + public function setCorridor(?string $corridor): self + { + $this->corridor = $corridor; + return $this; } /** - * Get customs informations in the address + * Store custom informations in the address. * - * @return array - */ - public function getCustoms(): array - { - return $this->customs; - } - - /** - * Store custom informations in the address - * - * @param array $customs * @return $this */ public function setCustoms(array $customs): self @@ -310,6 +328,142 @@ class Address return $this; } + public function setDistribution(?string $distribution): self + { + $this->distribution = $distribution; + + return $this; + } + + public function setExtra(?string $extra): self + { + $this->extra = $extra; + + return $this; + } + + public function setFlat(?string $flat): self + { + $this->flat = $flat; + + return $this; + } + + public function setFloor(?string $floor): self + { + $this->floor = $floor; + + return $this; + } + + /** + * Set IsNoAddress. + * + * Indicate true if the address is a fake address (homeless, ...) + * + * @return $this + */ + public function setIsNoAddress(bool $isNoAddress) + { + $this->isNoAddress = $isNoAddress; + + return $this; + } + + public function setLinkedToThirdParty($linkedToThirdParty): self + { + $this->linkedToThirdParty = $linkedToThirdParty; + + return $this; + } + + public function setPoint(?Point $point): self + { + $this->point = $point; + + return $this; + } + + /** + * Set postcode. + * + * @param PostalCode $postcode + * + * @return Address + */ + public function setPostcode(?PostalCode $postcode = null) + { + $this->postcode = $postcode; + + return $this; + } + + public function setSteps(?string $steps): self + { + $this->steps = $steps; + + return $this; + } + + public function setStreet(string $street): self + { + $this->street = $street; + + return $this; + } + + /** + * Set streetAddress1 (legacy function). + * + * @param string $streetAddress1 + * + * @return Address + */ + public function setStreetAddress1($streetAddress1) + { + $this->street = null === $streetAddress1 ? '' : $streetAddress1; + + return $this; + } + + /** + * Set streetAddress2 (legacy function). + * + * @param string $streetAddress2 + * + * @return Address + */ + public function setStreetAddress2($streetAddress2) + { + $this->streetNumber = null === $streetAddress2 ? '' : $streetAddress2; + + return $this; + } + + public function setStreetNumber(string $streetNumber): self + { + $this->streetNumber = $streetNumber; + + return $this; + } + + /** + * @return Address + */ + public function setValidFrom(DateTime $validFrom) + { + $this->validFrom = $validFrom; + + return $this; + } + + public function setValidTo(DateTimeInterface $validTo): self + { + $this->validTo = $validTo; + + return $this; + } + /** * Validate the address. * @@ -320,14 +474,13 @@ class Address * * the valid from is not null * * the address street 1 is greater than 2 * - * @param ExecutionContextInterface $context * @param array $payload */ public function validate(ExecutionContextInterface $context, $payload) { - if (!$this->getValidFrom() instanceof \DateTime) { + if (!$this->getValidFrom() instanceof DateTime) { $context - ->buildViolation("address.date-should-be-set") + ->buildViolation('address.date-should-be-set') ->atPath('validFrom') ->addViolation(); } @@ -338,176 +491,16 @@ class Address if (empty($this->getStreetAddress1())) { $context - ->buildViolation("address.street1-should-be-set") + ->buildViolation('address.street1-should-be-set') ->atPath('streetAddress1') ->addViolation(); } if (!$this->getPostcode() instanceof PostalCode) { $context - ->buildViolation("address.postcode-should-be-set") + ->buildViolation('address.postcode-should-be-set') ->atPath('postCode') ->addViolation(); } } - - /** - * @param Address $original - * @return Address - */ - public static function createFromAddress(Address $original) : Address - { - return (new Address()) - ->setPostcode($original->getPostcode()) - ->setStreetAddress1($original->getStreetAddress1()) - ->setStreetAddress2($original->getStreetAddress2()) - ->setValidFrom($original->getValidFrom()) - ; - } - - public function getStreet(): ?string - { - return $this->street; - } - - public function setStreet(string $street): self - { - $this->street = $street; - - return $this; - } - - public function getStreetNumber(): ?string - { - return $this->streetNumber; - } - - public function setStreetNumber(string $streetNumber): self - { - $this->streetNumber = $streetNumber; - - return $this; - } - - public function getFloor(): ?string - { - return $this->floor; - } - - public function setFloor(?string $floor): self - { - $this->floor = $floor; - - return $this; - } - - public function getCorridor(): ?string - { - return $this->corridor; - } - - public function setCorridor(?string $corridor): self - { - $this->corridor = $corridor; - - return $this; - } - - public function getSteps(): ?string - { - return $this->steps; - } - - public function setSteps(?string $steps): self - { - $this->steps = $steps; - - return $this; - } - - public function getBuildingName(): ?string - { - return $this->buildingName; - } - - public function setBuildingName(?string $buildingName): self - { - $this->buildingName = $buildingName; - - return $this; - } - - public function getFlat(): ?string - { - return $this->flat; - } - - public function setFlat(?string $flat): self - { - $this->flat = $flat; - - return $this; - } - - public function getDistribution(): ?string - { - return $this->distribution; - } - - public function setDistribution(?string $distribution): self - { - $this->distribution = $distribution; - - return $this; - } - - public function getExtra(): ?string - { - return $this->extra; - } - - public function setExtra(?string $extra): self - { - $this->extra = $extra; - - return $this; - } - - public function getValidTo(): ?\DateTimeInterface - { - return $this->validTo; - } - - public function setValidTo(\DateTimeInterface $validTo): self - { - $this->validTo = $validTo; - - return $this; - } - - public function getPoint(): ?Point - { - return $this->point; - } - - public function setPoint(?Point $point): self - { - $this->point = $point; - - return $this; - } - - public function getLinkedToThirdParty() - { - return $this->linkedToThirdParty; - } - - public function setLinkedToThirdParty($linkedToThirdParty): self - { - $this->linkedToThirdParty = $linkedToThirdParty; - - return $this; - } - } - diff --git a/src/Bundle/ChillMainBundle/Entity/AddressReference.php b/src/Bundle/ChillMainBundle/Entity/AddressReference.php index 944cab81b..413a99d73 100644 --- a/src/Bundle/ChillMainBundle/Entity/AddressReference.php +++ b/src/Bundle/ChillMainBundle/Entity/AddressReference.php @@ -1,15 +1,21 @@ id; } - public function getRefId(): ?string + public function getMunicipalityCode(): ?string { - return $this->refId; + return $this->municipalityCode; } - public function setRefId(string $refId): self + public function getPoint(): ?Point { - $this->refId = $refId; - - return $this; - } - - public function getStreet(): ?string - { - return $this->street; - } - - public function setStreet(?string $street): self - { - $this->street = $street; - - return $this; - } - - public function getStreetNumber(): ?string - { - return $this->streetNumber; - } - - public function setStreetNumber(?string $streetNumber): self - { - $this->streetNumber = $streetNumber; - - return $this; + return $this->point; } /** - * Set postcode - * - * @param PostalCode $postcode - * - * @return Address - */ - public function setPostcode(PostalCode $postcode = null) - { - $this->postcode = $postcode; - - return $this; - } - - /** - * Get postcode + * Get postcode. * * @return PostalCode */ @@ -127,9 +92,24 @@ class AddressReference return $this->postcode; } - public function getMunicipalityCode(): ?string + public function getRefId(): ?string { - return $this->municipalityCode; + return $this->refId; + } + + public function getSource(): ?string + { + return $this->source; + } + + public function getStreet(): ?string + { + return $this->street; + } + + public function getStreetNumber(): ?string + { + return $this->streetNumber; } public function setMunicipalityCode(?string $municipalityCode): self @@ -139,9 +119,32 @@ class AddressReference return $this; } - public function getSource(): ?string + public function setPoint(?Point $point): self { - return $this->source; + $this->point = $point; + + return $this; + } + + /** + * Set postcode. + * + * @param PostalCode $postcode + * + * @return Address + */ + public function setPostcode(?PostalCode $postcode = null) + { + $this->postcode = $postcode; + + return $this; + } + + public function setRefId(string $refId): self + { + $this->refId = $refId; + + return $this; } public function setSource(?string $source): self @@ -151,14 +154,16 @@ class AddressReference return $this; } - public function getPoint(): ?Point + public function setStreet(?string $street): self { - return $this->point; + $this->street = $street; + + return $this; } - public function setPoint(?Point $point): self + public function setStreetNumber(?string $streetNumber): self { - $this->point = $point; + $this->streetNumber = $streetNumber; return $this; } diff --git a/src/Bundle/ChillMainBundle/Entity/Center.php b/src/Bundle/ChillMainBundle/Entity/Center.php index b3792dab9..63f955554 100644 --- a/src/Bundle/ChillMainBundle/Entity/Center.php +++ b/src/Bundle/ChillMainBundle/Entity/Center.php @@ -1,40 +1,36 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="Chill\MainBundle\Repository\CenterRepository") * @ORM\Table(name="centers") - * - * @author Julien Fastré */ class Center implements HasCenterInterface { + /** + * @var Collection + * + * @ORM\OneToMany( + * targetEntity="Chill\MainBundle\Entity\GroupCenter", + * mappedBy="center" + * ) + */ + private $groupCenters; /** - * @var integer + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -48,18 +44,7 @@ class Center implements HasCenterInterface * @ORM\Column(type="string", length=255) */ private $name; - - /** - * @var Collection - * - * @ORM\OneToMany( - * targetEntity="Chill\MainBundle\Entity\GroupCenter", - * mappedBy="center" - * ) - */ - private $groupCenters; - - + /** * Center constructor. */ @@ -67,51 +52,7 @@ class Center implements HasCenterInterface { $this->groupCenters = new \Doctrine\Common\Collections\ArrayCollection(); } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param $name - * @return $this - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - - /** - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * @return ArrayCollection|Collection - */ - public function getGroupCenters() - { - return $this->groupCenters; - } - - /** - * @param GroupCenter $groupCenter - * @return $this - */ - public function addGroupCenter(GroupCenter $groupCenter) - { - $this->groupCenters->add($groupCenter); - return $this; - } - + /** * @return string */ @@ -119,7 +60,17 @@ class Center implements HasCenterInterface { return $this->getName(); } - + + /** + * @return $this + */ + public function addGroupCenter(GroupCenter $groupCenter) + { + $this->groupCenters->add($groupCenter); + + return $this; + } + /** * @return $this|Center */ @@ -128,4 +79,39 @@ class Center implements HasCenterInterface return $this; } + /** + * @return ArrayCollection|Collection + */ + public function getGroupCenters() + { + return $this->groupCenters; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } } diff --git a/src/Bundle/ChillMainBundle/Entity/Country.php b/src/Bundle/ChillMainBundle/Entity/Country.php index f8f68c3f3..28cdbfbb2 100644 --- a/src/Bundle/ChillMainBundle/Entity/Country.php +++ b/src/Bundle/ChillMainBundle/Entity/Country.php @@ -1,21 +1,35 @@ id; - } - - /** - * Set name - * - * @param string $name - * @return Country - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name - * - * @return string - */ - public function getName() - { - return $this->name; - } - /** * @return string */ @@ -80,7 +53,6 @@ class Country } /** - * * @return the string */ public function getCountryCode() @@ -89,13 +61,46 @@ class Country } /** + * Get id. * - * @param string $countryCode + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get name. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @param string $countryCode */ public function setCountryCode($countryCode) { $this->countryCode = $countryCode; + + return $this; + } + + /** + * Set name. + * + * @param string $name + * + * @return Country + */ + public function setName($name) + { + $this->name = $name; + return $this; } - } diff --git a/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php b/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php index 730d530d5..2ee0d7f58 100644 --- a/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php +++ b/src/Bundle/ChillMainBundle/Entity/Embeddable/CommentEmbeddable.php @@ -1,12 +1,19 @@ comment = $comment; + return $this->date; } /** @@ -54,26 +62,26 @@ class CommentEmbeddable } /** - * @param integer $userId + * @param string $comment + */ + public function setComment(?string $comment) + { + $this->comment = $comment; + } + + /** + * @param DateTime $date + */ + public function setDate(?DateTime $date) + { + $this->date = $date; + } + + /** + * @param int $userId */ public function setUserId($userId) { $this->userId = $userId; } - - /** - * @return \DateTime - */ - public function getDate() - { - return $this->date; - } - - /** - * @param \DateTime $date - */ - public function setDate(?\DateTime $date) - { - $this->date = $date; - } } diff --git a/src/Bundle/ChillMainBundle/Entity/GroupCenter.php b/src/Bundle/ChillMainBundle/Entity/GroupCenter.php index fee1081ff..dd0f700e9 100644 --- a/src/Bundle/ChillMainBundle/Entity/GroupCenter.php +++ b/src/Bundle/ChillMainBundle/Entity/GroupCenter.php @@ -1,49 +1,25 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Entity\PermissionsGroup; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="group_centers") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") - * - * @author Julien Fastré */ class GroupCenter { - /** - * @var int - * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - /** * @var Center * @@ -54,7 +30,26 @@ class GroupCenter * @ORM\Cache(usage="NONSTRICT_READ_WRITE") */ private $center; - + + /** + * @var int + * + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var PermissionsGroup + * + * @ORM\ManyToOne( + * targetEntity="Chill\MainBundle\Entity\PermissionsGroup", + * inversedBy="groupCenters") + * @ORM\Cache(usage="NONSTRICT_READ_WRITE") + */ + private $permissionsGroup; + /** * @var Collection * @@ -64,18 +59,7 @@ class GroupCenter * ) */ private $users; - - /** - * @var PermissionsGroup - * - * @ORM\ManyToOne( - * targetEntity="Chill\MainBundle\Entity\PermissionsGroup", - * inversedBy="groupCenters") - * @ORM\Cache(usage="NONSTRICT_READ_WRITE") - */ - private $permissionsGroup; - - + /** * GroupCenter constructor. */ @@ -84,14 +68,6 @@ class GroupCenter $this->permissionsGroup = new ArrayCollection(); $this->users = new ArrayCollection(); } - - /** - * @return int - */ - public function getId() - { - return $this->id; - } /** * @return Center @@ -102,23 +78,13 @@ class GroupCenter } /** - * @param Center $center - * @return \Chill\MainBundle\Entity\GroupCenter + * @return int */ - public function setCenter(Center $center) + public function getId() { - $this->center = $center; - return $this; + return $this->id; } - - /** - * @return ArrayCollection|Collection - */ - public function getUsers() - { - return $this->users; - } - + /** * @return PermissionGroup */ @@ -128,17 +94,30 @@ class GroupCenter } /** - * @param \Chill\MainBundle\Entity\PermissionsGroup $permissionGroup + * @return ArrayCollection|Collection + */ + public function getUsers() + { + return $this->users; + } + + /** + * @return \Chill\MainBundle\Entity\GroupCenter + */ + public function setCenter(Center $center) + { + $this->center = $center; + + return $this; + } + + /** * @return \Chill\MainBundle\Entity\GroupCenter */ public function setPermissionsGroup(PermissionsGroup $permissionsGroup) { $this->permissionsGroup = $permissionsGroup; + return $this; } - - - - - } diff --git a/src/Bundle/ChillMainBundle/Entity/HasCenterInterface.php b/src/Bundle/ChillMainBundle/Entity/HasCenterInterface.php index 8d6d541d8..a917662ca 100644 --- a/src/Bundle/ChillMainBundle/Entity/HasCenterInterface.php +++ b/src/Bundle/ChillMainBundle/Entity/HasCenterInterface.php @@ -1,35 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; /** - * Interface for entities which may be linked to a center - * - * - * @author Julien Fastré + * Interface for entities which may be linked to a center. */ interface HasCenterInterface { /** - * the linked center - * + * the linked center. + * * @return Center */ public function getCenter(); diff --git a/src/Bundle/ChillMainBundle/Entity/HasScopeInterface.php b/src/Bundle/ChillMainBundle/Entity/HasScopeInterface.php index 344d58557..cf93b7326 100644 --- a/src/Bundle/ChillMainBundle/Entity/HasScopeInterface.php +++ b/src/Bundle/ChillMainBundle/Entity/HasScopeInterface.php @@ -1,34 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; /** - * Interface for entities which have a scop - * - * @author Julien Fastré + * Interface for entities which have a scop. */ interface HasScopeInterface { /** - * Return the linked scope - * + * Return the linked scope. + * * @return Scope */ public function getScope(); diff --git a/src/Bundle/ChillMainBundle/Entity/Language.php b/src/Bundle/ChillMainBundle/Entity/Language.php index 2f59eda6d..d8793b7d4 100644 --- a/src/Bundle/ChillMainBundle/Entity/Language.php +++ b/src/Bundle/ChillMainBundle/Entity/Language.php @@ -1,21 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; @@ -23,19 +12,19 @@ namespace Chill\MainBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * Language + * Language. * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="language") * @ORM\Cache(usage="READ_ONLY", region="language_cache_region") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class Language { /** * @var string * - * @ORM\Id() + * @ORM\Id * @ORM\Column(type="string") */ private $id; @@ -48,9 +37,9 @@ class Language private $name; /** - * Get id + * Get id. * - * @return string + * @return string */ public function getId() { @@ -58,37 +47,40 @@ class Language } /** - * Set id - * + * Get name. + * + * @return string array + */ + public function getName() + { + return $this->name; + } + + /** + * Set id. + * * @param string $id + * * @return Language */ public function setId($id) { $this->id = $id; + return $this; } /** - * Set name + * Set name. * * @param string array $name + * * @return Language */ public function setName($name) { $this->name = $name; - + return $this; } - - /** - * Get name - * - * @return string array - */ - public function getName() - { - return $this->name; - } } diff --git a/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php b/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php index 8be256595..150312f42 100644 --- a/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php +++ b/src/Bundle/ChillMainBundle/Entity/PermissionsGroup.php @@ -1,74 +1,34 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; -use Chill\MainBundle\Entity\RoleScope; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; +use RuntimeException; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="permission_groups") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") - * - * @author Julien Fastré */ class PermissionsGroup { - /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - - /** - * @var string - * - * @ORM\Column(type="string", length=255) - */ - private $name; - /** * @var string[] * * @ORM\Column(type="json") */ private $flags = []; - - /** - * @var Collection - * - * @ORM\ManyToMany( - * targetEntity="Chill\MainBundle\Entity\RoleScope", - * inversedBy="permissionsGroups", - * cascade={ "persist" }) - * @ORM\Cache(usage="NONSTRICT_READ_WRITE") - */ - private $roleScopes; - + /** * @var Collection * @@ -78,8 +38,34 @@ class PermissionsGroup * ) */ private $groupCenters; - - + + /** + * @var int + * + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var string + * + * @ORM\Column(type="string", length=255) + */ + private $name; + + /** + * @var Collection + * + * @ORM\ManyToMany( + * targetEntity="Chill\MainBundle\Entity\RoleScope", + * inversedBy="permissionsGroups", + * cascade={ "persist" }) + * @ORM\Cache(usage="NONSTRICT_READ_WRITE") + */ + private $roleScopes; + /** * PermissionsGroup constructor. */ @@ -88,7 +74,20 @@ class PermissionsGroup $this->roleScopes = new \Doctrine\Common\Collections\ArrayCollection(); $this->groupCenters = new \Doctrine\Common\Collections\ArrayCollection(); } - + + public function addRoleScope(RoleScope $roleScope) + { + $this->roleScopes->add($roleScope); + } + + /** + * @return string[] + */ + public function getFlags() + { + return $this->flags; + } + /** * @return int */ @@ -104,7 +103,7 @@ class PermissionsGroup { return $this->name; } - + /** * @return ArrayCollection|Collection */ @@ -112,78 +111,62 @@ class PermissionsGroup { return $this->roleScopes; } - + /** - * @param $name - * @return $this + * Test that a role scope is associated only once + * with the permission group. */ - public function setName($name) + public function isRoleScopePresentOnce(ExecutionContextInterface $context) { - $this->name = $name; - return $this; + $roleScopesId = array_map( + function (RoleScope $roleScope) { + return $roleScope->getId(); + }, + $this->getRoleScopes()->toArray() + ); + $countedIds = array_count_values($roleScopesId); + + foreach ($countedIds as $id => $nb) { + if (1 < $nb) { + $context->buildViolation('A permission is already present ' + . 'for the same role and scope') + ->addViolation(); + } + } } /** - * @param RoleScope $roleScope - */ - public function addRoleScope(RoleScope $roleScope) - { - $this->roleScopes->add($roleScope); - } - - /** - * @param RoleScope $roleScope - * @throws \RuntimeException if the roleScope could not be removed. + * @throws RuntimeException if the roleScope could not be removed. */ public function removeRoleScope(RoleScope $roleScope) { $result = $this->roleScopes->removeElement($roleScope); - if ($result === FALSE) { - throw new \RuntimeException(sprintf("The roleScope '%s' could not be removed, " - . "aborting.", spl_object_hash($roleScope))); + + if (false === $result) { + throw new RuntimeException(sprintf("The roleScope '%s' could not be removed, " + . 'aborting.', spl_object_hash($roleScope))); } } - + /** - * @return string[] - */ - public function getFlags() - { - return $this->flags; - } - - /** - * @param array $flags * @return $this */ public function setFlags(array $flags) { $this->flags = $flags; - + return $this; } - - /** - * Test that a role scope is associated only once - * with the permission group - * - * @param ExecutionContextInterface $context - */ - public function isRoleScopePresentOnce(ExecutionContextInterface $context) - { - $roleScopesId = array_map(function(RoleScope $roleScope) { - return $roleScope->getId(); - }, - $this->getRoleScopes()->toArray()); - $countedIds = array_count_values($roleScopesId); - - foreach ($countedIds as $id => $nb) { - if ($nb > 1) { - $context->buildViolation("A permission is already present " - . "for the same role and scope") - ->addViolation(); - } - } - } + /** + * @param $name + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } } diff --git a/src/Bundle/ChillMainBundle/Entity/PostalCode.php b/src/Bundle/ChillMainBundle/Entity/PostalCode.php index 3cff0a6bf..b4959e3e2 100644 --- a/src/Bundle/ChillMainBundle/Entity/PostalCode.php +++ b/src/Bundle/ChillMainBundle/Entity/PostalCode.php @@ -1,26 +1,46 @@ code; + } /** - * @var Country + * Get country. * - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Country") + * @return Country */ - private $country; - + public function getCountry() + { + return $this->country; + } /** - * Get id + * Get id. * - * @return integer + * @return int */ public function getId() { @@ -61,21 +86,7 @@ class PostalCode } /** - * Set name - * - * @param string $name - * - * @return PostalCode - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name + * Get name. * * @return string */ @@ -85,7 +96,7 @@ class PostalCode } /** - * Set code + * Set code. * * @param string $code * @@ -99,23 +110,13 @@ class PostalCode } /** - * Get code - * - * @return string - */ - public function getCode() - { - return $this->code; - } - - /** - * Set country + * Set country. * * @param Country $country * * @return PostalCode */ - public function setCountry(Country $country = null) + public function setCountry(?Country $country = null) { $this->country = $country; @@ -123,13 +124,16 @@ class PostalCode } /** - * Get country + * Set name. * - * @return Country + * @param string $name + * + * @return PostalCode */ - public function getCountry() + public function setName($name) { - return $this->country; + $this->name = $name; + + return $this; } } - diff --git a/src/Bundle/ChillMainBundle/Entity/RoleScope.php b/src/Bundle/ChillMainBundle/Entity/RoleScope.php index 9944a96cc..f0ce6d54e 100644 --- a/src/Bundle/ChillMainBundle/Entity/RoleScope.php +++ b/src/Bundle/ChillMainBundle/Entity/RoleScope.php @@ -1,83 +1,70 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="role_scopes") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") - * - * @author Julien Fastré */ class RoleScope { /** - * @var integer + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + + /** + * @var Collection + * + * @ORM\ManyToMany( + * targetEntity="Chill\MainBundle\Entity\PermissionsGroup", + * mappedBy="roleScopes") + */ + private $permissionsGroups; + /** * @var string * * @ORM\Column(type="string", length=255) */ private $role; - + /** * @var Scope * * @ORM\ManyToOne( * targetEntity="Chill\MainBundle\Entity\Scope", - * inversedBy="roleScopes") + * inversedBy="roleScopes") * @ORM\JoinColumn(nullable=true, name="scope_id") * @ORM\Cache(usage="NONSTRICT_READ_WRITE") */ private $scope; - - /** - * @var Collection - * - * @ORM\ManyToMany( - * targetEntity="Chill\MainBundle\Entity\PermissionsGroup", - * mappedBy="roleScopes") - */ - private $permissionsGroups; - - + /** * RoleScope constructor. */ - public function __construct() { + public function __construct() + { $this->new = true; $this->permissionsGroups = new ArrayCollection(); } - + /** * @return int */ @@ -101,9 +88,10 @@ class RoleScope { return $this->scope; } - + /** * @param type $role + * * @return RoleScope */ public function setRole($role) @@ -115,12 +103,13 @@ class RoleScope /** * @param Scope $scope + * * @return RoleScope */ - public function setScope(Scope $scope = null) + public function setScope(?Scope $scope = null) { $this->scope = $scope; - + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Entity/Scope.php b/src/Bundle/ChillMainBundle/Entity/Scope.php index 5a9e348d4..7304c6bcf 100644 --- a/src/Bundle/ChillMainBundle/Entity/Scope.php +++ b/src/Bundle/ChillMainBundle/Entity/Scope.php @@ -1,68 +1,53 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; -use Chill\MainBundle\Entity\RoleScope; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="scopes") * @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region") - * - * @author Julien Fastré */ class Scope { /** - * @var integer + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ private $id; - + /** - * translatable names - * + * translatable names. + * * @var array * * @ORM\Column(type="json_array") */ private $name = []; - + /** * @var Collection * * @ORM\OneToMany( * targetEntity="Chill\MainBundle\Entity\RoleScope", - * mappedBy="scope") + * mappedBy="scope") * @ORM\Cache(usage="NONSTRICT_READ_WRITE") */ private $roleScopes; - - + /** * Scope constructor. */ @@ -70,7 +55,12 @@ class Scope { $this->roleScopes = new ArrayCollection(); } - + + public function addRoleScope(RoleScope $roleScope) + { + $this->roleScopes->add($roleScope); + } + /** * @return int */ @@ -86,17 +76,7 @@ class Scope { return $this->name; } - - /** - * @param $name - * @return $this - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - + /** * @return Collection */ @@ -104,12 +84,16 @@ class Scope { return $this->roleScopes; } - + /** - * @param RoleScope $roleScope + * @param $name + * + * @return $this */ - public function addRoleScope(RoleScope $roleScope) + public function setName($name) { - $this->roleScopes->add($roleScope); + $this->name = $name; + + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index 1a46b30a5..1173c8ee1 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -1,24 +1,32 @@ groupCenters = new ArrayCollection(); } - + /** * @return string */ @@ -126,86 +136,35 @@ class User implements AdvancedUserInterface { } /** - * Get id + * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter * - * @return integer + * @return \Chill\MainBundle\Entity\User */ - public function getId() + public function addGroupCenter(GroupCenter $groupCenter) + { + $this->groupCenters->add($groupCenter); + + return $this; + } + + public function eraseCredentials() { - return $this->id; } /** - * Set username + * Get attributes. * - * @param string $name - * @return Agent - */ - public function setUsername($name) - { - $this->username = $name; - - return $this; - } - - /** - * @return string - */ - public function getUsername() - { - return $this->username; - } - - /** - */ - public function eraseCredentials() {} - - /** * @return array */ - public function getRoles() + public function getAttributes() { - return array('ROLE_USER'); + if (null === $this->attributes) { + $this->attributes = []; + } + + return $this->attributes; } - - /** - * @return null|string - */ - public function getSalt() - { - return $this->salt; - } - - /** - * @param $usernameCanonical - * @return $this - */ - public function setUsernameCanonical($usernameCanonical) - { - $this->usernameCanonical = $usernameCanonical; - - return $this; - } - - /** - * @return string - */ - public function getUsernameCanonical() - { - return $this->usernameCanonical; - } - - /** - * @param $email - * @return $this - */ - public function setEmail($email) - { - $this->email = $email; - - return $this; - } - + /** * @return string */ @@ -213,18 +172,7 @@ class User implements AdvancedUserInterface { { return $this->email; } - - /** - * @param $emailCanonical - * @return $this - */ - public function setEmailCanonical($emailCanonical) - { - $this->emailCanonical = $emailCanonical; - - return $this; - } - + /** * @return string */ @@ -232,16 +180,23 @@ class User implements AdvancedUserInterface { { return $this->emailCanonical; } - + /** - * @param $password - * @return $this + * @return GroupCenter */ - function setPassword($password) + public function getGroupCenters() { - $this->password = $password; - - return $this; + return $this->groupCenters; + } + + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; } /** @@ -251,17 +206,39 @@ class User implements AdvancedUserInterface { { return $this->password; } - + /** - * @param $salt - * @return $this + * @return array */ - function setSalt($salt) + public function getRoles() { - $this->salt = $salt; - return $this; + return ['ROLE_USER']; } - + + /** + * @return string|null + */ + public function getSalt() + { + return $this->salt; + } + + /** + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * @return string + */ + public function getUsernameCanonical() + { + return $this->usernameCanonical; + } + /** * @return bool */ @@ -269,7 +246,7 @@ class User implements AdvancedUserInterface { { return true; } - + /** * @return bool */ @@ -277,7 +254,7 @@ class User implements AdvancedUserInterface { { return $this->locked; } - + /** * @return bool */ @@ -285,7 +262,7 @@ class User implements AdvancedUserInterface { { return true; } - + /** * @return bool */ @@ -293,60 +270,20 @@ class User implements AdvancedUserInterface { { return $this->enabled; } - + /** - * @param bool $enabled - */ - public function setEnabled($enabled) - { - $this->enabled = $enabled; - - return $this; - } - - /** - * @return GroupCenter - */ - public function getGroupCenters() - { - return $this->groupCenters; - } - - /** - * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter - * @return \Chill\MainBundle\Entity\User - */ - public function addGroupCenter(GroupCenter $groupCenter) - { - $this->groupCenters->add($groupCenter); - return $this; - } - - /** - * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter - * @throws \RuntimeException if the groupCenter is not in the collection - */ - public function removeGroupCenter(GroupCenter $groupCenter) - { - if ($this->groupCenters->removeElement($groupCenter) === FALSE) { - throw new \RuntimeException(sprintf("The groupCenter could not be removed, " - . "it seems not to be associated with the user. Aborting.")); - } - } - - /** - * This function check that groupCenter are present only once. The validator + * This function check that groupCenter are present only once. The validator * use this function to avoid a user to be associated to the same groupCenter * more than once. */ public function isGroupCenterPresentOnce(ExecutionContextInterface $context) { - $groupCentersIds = array(); + $groupCentersIds = []; + foreach ($this->getGroupCenters() as $groupCenter) { if (in_array($groupCenter->getId(), $groupCentersIds)) { - $context->buildViolation("The user has already those permissions") - ->addViolation(); - + $context->buildViolation('The user has already those permissions') + ->addViolation(); } else { $groupCentersIds[] = $groupCenter->getId(); } @@ -354,7 +291,20 @@ class User implements AdvancedUserInterface { } /** - * Set attributes + * @param \Chill\MainBundle\Entity\GroupCenter $groupCenter + * + * @throws RuntimeException if the groupCenter is not in the collection + */ + public function removeGroupCenter(GroupCenter $groupCenter) + { + if ($this->groupCenters->removeElement($groupCenter) === false) { + throw new RuntimeException(sprintf('The groupCenter could not be removed, ' + . 'it seems not to be associated with the user. Aborting.')); + } + } + + /** + * Set attributes. * * @param array $attributes * @@ -368,16 +318,86 @@ class User implements AdvancedUserInterface { } /** - * Get attributes + * @param $email * - * @return array + * @return $this */ - public function getAttributes() + public function setEmail($email) { - if ($this->attributes === null) { - $this->attributes = []; - } + $this->email = $email; - return $this->attributes; + return $this; + } + + /** + * @param $emailCanonical + * + * @return $this + */ + public function setEmailCanonical($emailCanonical) + { + $this->emailCanonical = $emailCanonical; + + return $this; + } + + /** + * @param bool $enabled + */ + public function setEnabled($enabled) + { + $this->enabled = $enabled; + + return $this; + } + + /** + * @param $password + * + * @return $this + */ + public function setPassword($password) + { + $this->password = $password; + + return $this; + } + + /** + * @param $salt + * + * @return $this + */ + public function setSalt($salt) + { + $this->salt = $salt; + + return $this; + } + + /** + * Set username. + * + * @param string $name + * + * @return Agent + */ + public function setUsername($name) + { + $this->username = $name; + + return $this; + } + + /** + * @param $usernameCanonical + * + * @return $this + */ + public function setUsernameCanonical($usernameCanonical) + { + $this->usernameCanonical = $usernameCanonical; + + return $this; } } diff --git a/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php b/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php index db65600bd..ece594903 100644 --- a/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php +++ b/src/Bundle/ChillMainBundle/Export/AggregatorInterface.php @@ -1,69 +1,48 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; +use Closure; + /** - * Interface for Aggregators. - * + * Interface for Aggregators. + * * Aggregators gather result of a query. Most of the time, it will add * a GROUP BY clause. - * - * @author Julien Fastré */ interface AggregatorInterface extends ModifierInterface -{ - /** - * give the list of keys the current export added to the queryBuilder in - * self::initiateQuery - * - * Example: if your query builder will contains `SELECT count(id) AS count_id ...`, - * this function will return `array('count_id')`. - * - * @param mixed[] $data the data from the export's form (added by self::buildForm) - */ - public function getQueryKeys($data); - +{ /** * get a callable which will be able to transform the results into * viewable and understable string. - * - * The callable will have only one argument: the `value` to translate. - * + * + * The callable will have only one argument: the `value` to translate. + * * The callable should also be able to return a key `_header`, which - * will contains the header of the column. - * - * The string returned **must** be already translated if necessary, + * will contains the header of the column. + * + * The string returned **must** be already translated if necessary, * **with an exception** for the string returned for `_header`. - * - * Example : - * + * + * Example : + * * ``` * protected $translator; - * + * * public function getLabels($key, array $values, $data) * { * return function($value) { * case $value * { - * case '_header' : - * return 'my header not translated'; + * case '_header' : + * return 'my header not translated'; * case true: * return $this->translator->trans('true'); * case false: @@ -74,17 +53,28 @@ interface AggregatorInterface extends ModifierInterface * } * } * ``` - * - * **Note:** Why each string must be translated with an exception for + * + * **Note:** Why each string must be translated with an exception for * the `_header` ? For performance reasons: most of the value will be number * which do not need to be translated, or value already translated in * database. But the header must be, in every case, translated. - * + * * @param string $key The column key, as added in the query * @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR') * @param mixed $data The data from the export's form (as defined in `buildForm` - * @return \Closure where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }` + * + * @return Closure where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); ` */ public function getLabels($key, array $values, $data); + /** + * give the list of keys the current export added to the queryBuilder in + * self::initiateQuery. + * + * Example: if your query builder will contains `SELECT count(id) AS count_id ...`, + * this function will return `array('count_id')`. + * + * @param mixed[] $data the data from the export's form (added by self::buildForm) + */ + public function getQueryKeys($data); } diff --git a/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php b/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php index ea82175e9..4a8efc586 100644 --- a/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php +++ b/src/Bundle/ChillMainBundle/Export/DirectExportInterface.php @@ -1,37 +1,34 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; @@ -23,25 +13,19 @@ use Symfony\Component\Form\FormBuilderInterface; /** * The common methods between different object used to build export (i.e. : ExportInterface, - * FilterInterface, AggregatorInterface) - * - * @author Julien Fastré + * FilterInterface, AggregatorInterface). */ interface ExportElementInterface { /** - * get a title, which will be used in UI (and translated) - * + * Add a form to collect data from the user. + */ + public function buildForm(FormBuilderInterface $builder); + + /** + * get a title, which will be used in UI (and translated). + * * @return string */ public function getTitle(); - - - /** - * Add a form to collect data from the user. - * - * @param FormBuilderInterface $builder - */ - public function buildForm(FormBuilderInterface $builder); - } diff --git a/src/Bundle/ChillMainBundle/Export/ExportElementValidatedInterface.php b/src/Bundle/ChillMainBundle/Export/ExportElementValidatedInterface.php index cbc2f3881..c888b05c3 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportElementValidatedInterface.php +++ b/src/Bundle/ChillMainBundle/Export/ExportElementValidatedInterface.php @@ -1,46 +1,35 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Export; use Symfony\Component\Validator\Context\ExecutionContextInterface; /** - * Add a validation method to validate data collected by Export Element - * + * Add a validation method to validate data collected by Export Element. + * * Implements this interface on other `ExportElementInterface` to validate * the form submitted by users. - * + * * **note**: When this interface is implemented on filters or aggregators, * the form is validated **only** if the filter/aggregator is `enabled` by the * user. - * - * @link http://symfony.com/doc/current/validation/custom_constraint.html#class-constraint-validator Example of building violations * - * @author Julien Fastré + * @see http://symfony.com/doc/current/validation/custom_constraint.html#class-constraint-validator Example of building violations */ interface ExportElementValidatedInterface { /** * validate the form's data and, if required, build a contraint * violation on the data. - * + * * @param mixed $data the data, as returned by the user - * @param ExecutionContextInterface $context */ public function validateForm($data, ExecutionContextInterface $context); } diff --git a/src/Bundle/ChillMainBundle/Export/ExportElementsProviderInterface.php b/src/Bundle/ChillMainBundle/Export/ExportElementsProviderInterface.php index 077272c9b..b33237a4f 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportElementsProviderInterface.php +++ b/src/Bundle/ChillMainBundle/Export/ExportElementsProviderInterface.php @@ -1,30 +1,20 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Export; /** * Interface to provide export elements dynamically. - * - * The typical use case is providing exports or aggregators depending on + * + * The typical use case is providing exports or aggregators depending on * dynamic data. Example: providing exports for reports, reports depending * on data stored in database. - * - * @author Julien Fastré */ interface ExportElementsProviderInterface { diff --git a/src/Bundle/ChillMainBundle/Export/ExportInterface.php b/src/Bundle/ChillMainBundle/Export/ExportInterface.php index c260649d1..0bdaa1000 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportInterface.php +++ b/src/Bundle/ChillMainBundle/Export/ExportInterface.php @@ -1,143 +1,68 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; +use Closure; use Doctrine\ORM\QueryBuilder; /** * Interface for Export. - * - * An export is a class which will initiate a query for an export. - * - * **Note** : the report implementing this class will be modified by + * + * An export is a class which will initiate a query for an export. + * + * **Note** : the report implementing this class will be modified by * both filters **and** aggregators. If the report does not support * aggregation, use `ListInterface`. * * @example Chill\PersonBundle\Export\CountPerson an example of implementation - * @author Julien Fastré */ interface ExportInterface extends ExportElementInterface { - /** - * Return the Export's type. This will inform _on what_ export will apply. - * Most of the type, it will be a string which references an entity. - * - * Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE - * - * @return string - */ - public function getType(); - - /** - * A description, which will be used in the UI to explain what the export does. - * This description will be translated. - * - * @return string - */ - public function getDescription(); - - /** - * The initial query, which will be modified by ModifiersInterface - * (i.e. AggregatorInterface, FilterInterface). - * - * This query should take into account the `$acl` and restrict result only to - * what the user is allowed to see. (Do not show personal data the user - * is not allowed to see). - * - * The returned object should be an instance of QueryBuilder or NativeQuery. - * - * @param array $requiredModifiers - * @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )` - * @param array $data the data from the form, if any - * @return QueryBuilder|\Doctrine\ORM\NativeQuery the query to execute. - */ - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()); - - /** - * Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface) - * are allowed. The modifiers should be an array of types the _modifier_ apply on - * (@see ModifiersInterface::applyOn()). - * - * @return string[] - */ - public function supportsModifiers(); - - /** - * Return the required Role to execute the Export. - * - * @return \Symfony\Component\Security\Core\Role\Role - * - */ - public function requiredRole(); - /** * Return which formatter type is allowed for this report. - * + * * @return string[] */ public function getAllowedFormattersTypes(); - + /** - * give the list of keys the current export added to the queryBuilder in - * self::initiateQuery - * - * Example: if your query builder will contains `SELECT count(id) AS count_id ...`, - * this function will return `array('count_id')`. - * - * @param mixed[] $data the data from the export's form (added by self::buildForm) + * A description, which will be used in the UI to explain what the export does. + * This description will be translated. + * + * @return string */ - public function getQueryKeys($data); - - /** - * Return the results of the query builder. - * - * @param QueryBuilder|\Doctrine\ORM\NativeQuery $query - * @param mixed[] $data the data from the export's fomr (added by self::buildForm) - * @return mixed[] an array of results - */ - public function getResult($query, $data); - - + public function getDescription(); + /** * transform the results to viewable and understable string. - * - * The callable will have only one argument: the `value` to translate. - * + * + * The callable will have only one argument: the `value` to translate. + * * The callable should also be able to return a key `_header`, which - * will contains the header of the column. - * - * The string returned **must** be already translated if necessary, + * will contains the header of the column. + * + * The string returned **must** be already translated if necessary, * **with an exception** for the string returned for `_header`. - * - * Example : - * + * + * Example : + * * ``` * protected $translator; - * + * * public function getLabels($key, array $values, $data) * { * return function($value) { * case $value * { - * case '_header' : - * return 'my header not translated'; + * case '_header' : + * return 'my header not translated'; * case true: * return $this->translator->trans('true'); * case false: @@ -148,18 +73,81 @@ interface ExportInterface extends ExportElementInterface * } * } * ``` - * - * **Note:** Why each string must be translated with an exception for + * + * **Note:** Why each string must be translated with an exception for * the `_header` ? For performance reasons: most of the value will be number * which do not need to be translated, or value already translated in * database. But the header must be, in every case, translated. - * - * + * * @param string $key The column key, as added in the query * @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR') * @param mixed $data The data from the export's form (as defined in `buildForm` - * @return \Closure where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }` + * + * @return Closure where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); ` */ public function getLabels($key, array $values, $data); + /** + * give the list of keys the current export added to the queryBuilder in + * self::initiateQuery. + * + * Example: if your query builder will contains `SELECT count(id) AS count_id ...`, + * this function will return `array('count_id')`. + * + * @param mixed[] $data the data from the export's form (added by self::buildForm) + */ + public function getQueryKeys($data); + + /** + * Return the results of the query builder. + * + * @param \Doctrine\ORM\NativeQuery|QueryBuilder $query + * @param mixed[] $data the data from the export's fomr (added by self::buildForm) + * + * @return mixed[] an array of results + */ + public function getResult($query, $data); + + /** + * Return the Export's type. This will inform _on what_ export will apply. + * Most of the type, it will be a string which references an entity. + * + * Example of types : Chill\PersonBundle\Export\Declarations::PERSON_TYPE + * + * @return string + */ + public function getType(); + + /** + * The initial query, which will be modified by ModifiersInterface + * (i.e. AggregatorInterface, FilterInterface). + * + * This query should take into account the `$acl` and restrict result only to + * what the user is allowed to see. (Do not show personal data the user + * is not allowed to see). + * + * The returned object should be an instance of QueryBuilder or NativeQuery. + * + * @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )` + * @param array $data the data from the form, if any + * + * @return \Doctrine\ORM\NativeQuery|QueryBuilder the query to execute. + */ + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []); + + /** + * Return the required Role to execute the Export. + * + * @return \Symfony\Component\Security\Core\Role\Role + */ + public function requiredRole(); + + /** + * Inform which ModifiersInterface (i.e. AggregatorInterface, FilterInterface) + * are allowed. The modifiers should be an array of types the _modifier_ apply on + * (@see ModifiersInterface::applyOn()). + * + * @return string[] + */ + public function supportsModifiers(); } diff --git a/src/Bundle/ChillMainBundle/Export/ExportManager.php b/src/Bundle/ChillMainBundle/Export/ExportManager.php index d3ec7eabf..f0e5df9ed 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -1,154 +1,170 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; -use Chill\MainBundle\Export\FilterInterface; -use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Export\ExportInterface; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\HttpFoundation\Response; -use Psr\Log\LoggerInterface; +use Chill\MainBundle\Form\Type\Export\ExportType; +use Chill\MainBundle\Form\Type\Export\PickCenterType; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\MainBundle\Form\Type\Export\PickCenterType; +use Generator; +use InvalidArgumentException; +use LogicException; +use Psr\Log\LoggerInterface; +use RuntimeException; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; -use Chill\MainBundle\Form\Type\Export\ExportType; -use Chill\MainBundle\Export\ListInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use UnexpectedValueException; /** * Collects all agregators, filters and export from * the installed bundle, and performs the export logic. - * - * - * @author Julien Fastré */ class ExportManager { /** - * The collected filters, injected by DI - * - * @var FilterInterface[] - */ - private $filters = array(); - - /** - * The collected aggregators, injected by DI + * The collected aggregators, injected by DI. * * @var AggregatorInterface[] */ - private $aggregators = array(); - + private $aggregators = []; + /** - * Collected Exports, injected by DI + * @var AuthorizationChecker + */ + private $authorizationChecker; + + /** + * @var AuthorizationHelper + */ + private $authorizationHelper; + + /** + * @var EntityManagerInterface + */ + private $em; + + /** + * Collected Exports, injected by DI. * * @var ExportInterface[] */ - private $exports = array(); - + private $exports = []; + /** - * Collected Formatters, injected by DI + * The collected filters, injected by DI. + * + * @var FilterInterface[] + */ + private $filters = []; + + /** + * Collected Formatters, injected by DI. * * @var FormatterInterface[] */ - private $formatters = array(); - + private $formatters = []; + /** - * a logger + * a logger. * * @var LoggerInterface */ private $logger; - + /** - * - * @var EntityManagerInterface - */ - private $em; - - /** - * - * @var AuthorizationChecker - */ - private $authorizationChecker; - - /** - * - * @var AuthorizationHelper - */ - private $authorizationHelper; - - /** - * * @var \Symfony\Component\Security\Core\User\UserInterface */ private $user; - + public function __construct( - LoggerInterface $logger, - EntityManagerInterface $em, - AuthorizationCheckerInterface $authorizationChecker, - AuthorizationHelper $authorizationHelper, - TokenStorageInterface $tokenStorage) - { + LoggerInterface $logger, + EntityManagerInterface $em, + AuthorizationCheckerInterface $authorizationChecker, + AuthorizationHelper $authorizationHelper, + TokenStorageInterface $tokenStorage + ) { $this->logger = $logger; $this->em = $em; $this->authorizationChecker = $authorizationChecker; $this->authorizationHelper = $authorizationHelper; $this->user = $tokenStorage->getToken()->getUser(); } - + /** - * add a Filter - * - * @internal Normally used by the dependency injection - * - * @param FilterInterface $filter - * @param string $alias + * Return a \Generator containing filter which support type. If `$centers` is + * not null, restrict the given filters to the center the user have access to. + * + * if $centers is null, the function will returns all filters where the user + * has access in every centers he can reach (if the user can use the filter F in + * center A, but not in center B, the filter F will not be returned) + * + * @param \Chill\MainBundle\Entity\Center[] $centers the centers where the user have access to + * + * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias */ - public function addFilter(FilterInterface $filter, $alias) + public function &getFiltersApplyingOn(ExportInterface $export, ?array $centers = null) { - $this->filters[$alias] = $filter; + foreach ($this->filters as $alias => $filter) { + if ( + in_array($filter->applyOn(), $export->supportsModifiers()) + && $this->isGrantedForElement($filter, $export, $centers) + ) { + yield $alias => $filter; + } + } } - + /** - * add an aggregator - * + * Return a \Generator containing aggregators supported by the given export. + * + * @internal This class check the interface implemented by export, and, if ´ListInterface´ is used, return an empty array + * + * @return AggregatorInterface[] a \Generator that contains aggretagors. The key is the filter's alias + */ + public function &getAggregatorsApplyingOn(ExportInterface $export, ?array $centers = null) + { + if ($export instanceof ListInterface) { + return; + } + + foreach ($this->aggregators as $alias => $aggregator) { + if ( + in_array($aggregator->applyOn(), $export->supportsModifiers()) + && $this->isGrantedForElement($aggregator, $export, $centers) + ) { + yield $alias => $aggregator; + } + } + } + + /** + * add an aggregator. + * * @internal used by DI - * - * @param AggregatorInterface $aggregator + * * @param string $alias */ public function addAggregator(AggregatorInterface $aggregator, $alias) { $this->aggregators[$alias] = $aggregator; } - + /** - * add an export - * + * add an export. + * * @internal used by DI - * - * @param ExportInterface|DirectExportInterface $export + * + * @param DirectExportInterface|ExportInterface $export * @param type $alias */ public function addExport($export, $alias) @@ -156,30 +172,21 @@ class ExportManager if ($export instanceof ExportInterface || $export instanceof DirectExportInterface) { $this->exports[$alias] = $export; } else { - throw new \InvalidArgumentException(sprintf("The export with alias %s " - . "does not implements %s or %s.", $alias, ExportInterface::class, - DirectExportInterface::class)); + throw new InvalidArgumentException(sprintf( + 'The export with alias %s ' + . 'does not implements %s or %s.', + $alias, + ExportInterface::class, + DirectExportInterface::class + )); } } - - /** - * add a formatter - * - * @internal used by DI - * - * @param FormatterInterface $formatter - * @param type $alias - */ - public function addFormatter(FormatterInterface $formatter, $alias) - { - $this->formatters[$alias] = $formatter; - } - + public function addExportElementsProvider(ExportElementsProviderInterface $provider, $prefix) { foreach ($provider->getExportElements() as $suffix => $element) { - $alias = $prefix.'_'.$suffix; - + $alias = $prefix . '_' . $suffix; + if ($element instanceof ExportInterface) { $this->addExport($element, $alias); } elseif ($element instanceof FilterInterface) { @@ -189,33 +196,190 @@ class ExportManager } elseif ($element instanceof FormatterInterface) { $this->addFormatter($element, $alias); } else { - throw new \LogicException("This element ".\get_class($element)." " - . "is not an instance of export element"); + throw new LogicException('This element ' . \get_class($element) . ' ' + . 'is not an instance of export element'); } } } - + + /** + * add a Filter. + * + * @internal Normally used by the dependency injection + * + * @param string $alias + */ + public function addFilter(FilterInterface $filter, $alias) + { + $this->filters[$alias] = $filter; + } + + /** + * add a formatter. + * + * @internal used by DI + * + * @param type $alias + */ + public function addFormatter(FormatterInterface $formatter, $alias) + { + $this->formatters[$alias] = $formatter; + } + + /** + * Generate a response which contains the requested data. + * + * @param string $exportAlias + * @param mixed[] $data + * + * @return Response + */ + public function generate($exportAlias, array $pickedCentersData, array $data, array $formatterData) + { + $export = $this->getExport($exportAlias); + //$qb = $this->em->createQueryBuilder(); + $centers = $this->getPickedCenters($pickedCentersData); + + if ($export instanceof DirectExportInterface) { + return $export->generate( + $this->buildCenterReachableScopes($centers, $export), + $data[ExportType::EXPORT_KEY] + ); + } + + $query = $export->initiateQuery( + $this->retrieveUsedModifiers($data), + $this->buildCenterReachableScopes($centers, $export), + $data[ExportType::EXPORT_KEY] + ); + + if ($query instanceof \Doctrine\ORM\NativeQuery) { + // throw an error if the export require other modifier, which is + // not allowed when the export return a `NativeQuery` + if (count($export->supportsModifiers()) > 0) { + throw new LogicException("The export with alias `{$exportAlias}` return " + . 'a `\\Doctrine\\ORM\\NativeQuery` and supports modifiers, which is not ' + . 'allowed. Either the method `supportsModifiers` should return an empty ' + . 'array, or return a `Doctrine\\ORM\\QueryBuilder`'); + } + } elseif ($query instanceof QueryBuilder) { + //handle filters + $this->handleFilters($export, $query, $data[ExportType::FILTER_KEY], $centers); + + //handle aggregators + $this->handleAggregators($export, $query, $data[ExportType::AGGREGATOR_KEY], $centers); + + $this->logger->debug('current query is ' . $query->getDQL(), [ + 'class' => self::class, 'function' => __FUNCTION__, + ]); + } else { + throw new UnexpectedValueException('The method `intiateQuery` should return ' + . 'a `\\Doctrine\\ORM\\NativeQuery` or a `Doctrine\\ORM\\QueryBuilder` ' + . 'object.'); + } + + $result = $export->getResult($query, $data[ExportType::EXPORT_KEY]); + + if (!is_iterable($result)) { + throw new UnexpectedValueException( + sprintf( + 'The result of the export should be an iterable, %s given', + gettype($result) + ) + ); + } + + /* @var $formatter FormatterInterface */ + $formatter = $this->getFormatter($this->getFormatterAlias($data)); + $filtersData = []; + $aggregatorsData = []; + + if ($query instanceof QueryBuilder) { + $aggregators = $this->retrieveUsedAggregators($data[ExportType::AGGREGATOR_KEY]); + + foreach ($aggregators as $alias => $aggregator) { + $aggregatorsData[$alias] = $data[ExportType::AGGREGATOR_KEY][$alias]['form']; + } + } + + $filters = $this->retrieveUsedFilters($data[ExportType::FILTER_KEY]); + + foreach ($filters as $alias => $filter) { + $filtersData[$alias] = $data[ExportType::FILTER_KEY][$alias]['form']; + } + + return $formatter->getResponse( + $result, + $formatterData, + $exportAlias, + $data[ExportType::EXPORT_KEY], + $filtersData, + $aggregatorsData + ); + } + + /** + * @param string $alias + * + * @throws RuntimeException if the aggregator is not known + * + * @return AggregatorInterface + */ + public function getAggregator($alias) + { + if (!array_key_exists($alias, $this->aggregators)) { + throw new RuntimeException("The aggregator with alias {$alias} is not known."); + } + + return $this->aggregators[$alias]; + } + + public function getAggregators(array $aliases) + { + foreach ($aliases as $alias) { + yield $alias => $this->getAggregator($alias); + } + } + /** - * * @return string[] the existing type for known exports */ public function getExistingExportsTypes() { - $existingTypes = array(); - - foreach($this->exports as $export) { + $existingTypes = []; + + foreach ($this->exports as $export) { if (!in_array($export->getType(), $existingTypes)) { array_push($existingTypes, $export->getType()); } } - + return $existingTypes; } - + + /** + * Return an export by his alias. + * + * @param string $alias + * + * @throws RuntimeException + * + * @return ExportInterface + */ + public function getExport($alias) + { + if (!array_key_exists($alias, $this->exports)) { + throw new RuntimeException("The export with alias {$alias} is not known."); + } + + return $this->exports[$alias]; + } + /** * Return all exports. The exports's alias are the array's keys. - * - * @param boolean $whereUserIsGranted if true (default), restrict to user which are granted the right to execute the export + * + * @param bool $whereUserIsGranted if true (default), restrict to user which are granted the right to execute the export + * * @return ExportInterface[] an array where export's alias are keys */ public function getExports($whereUserIsGranted = true) @@ -230,16 +394,18 @@ class ExportManager } } } - + /** * Get all exports grouped in an array. - * + * * @param bool $whereUserIsGranted + * * @return array where keys are the groups's name and value is an array of exports */ public function getExportsGrouped($whereUserIsGranted = true): array { - $groups = [ '_' => [] ]; + $groups = ['_' => []]; + foreach ($this->getExports($whereUserIsGranted) as $alias => $export) { if ($export instanceof GroupedExportInterface) { $groups[$export->getGroup()][$alias] = $export; @@ -247,90 +413,66 @@ class ExportManager $groups['_'][$alias] = $export; } } - + return $groups; } - + /** - * Return an export by his alias - * - * @param string $alias - * @return ExportInterface - * @throws \RuntimeException - */ - public function getExport($alias) - { - if (!array_key_exists($alias, $this->exports)) { - throw new \RuntimeException("The export with alias $alias is not known."); - } - - return $this->exports[$alias]; - } - - /** - * * @param string $alias + * + * @throws RuntimeException if the filter is not known + * * @return FilterInterface - * @throws \RuntimeException if the filter is not known */ public function getFilter($alias) { if (!array_key_exists($alias, $this->filters)) { - throw new \RuntimeException("The filter with alias $alias is not known."); + throw new RuntimeException("The filter with alias {$alias} is not known."); } - + return $this->filters[$alias]; } - + /** - * get all filters - * - * @param \Generator $aliases + * get all filters. + * + * @param Generator $aliases */ public function getFilters(array $aliases) { - foreach($aliases as $alias) { + foreach ($aliases as $alias) { yield $alias => $this->getFilter($alias); } } - - /** - * - * @param string $alias - * @return AggregatorInterface - * @throws \RuntimeException if the aggregator is not known - */ - public function getAggregator($alias) - { - if (!array_key_exists($alias, $this->aggregators)) { - throw new \RuntimeException("The aggregator with alias $alias is not known."); - } - - return $this->aggregators[$alias]; - } - - public function getAggregators(array $aliases) - { - foreach ($aliases as $alias) { - yield $alias => $this->getAggregator($alias); - } - } - + public function getFormatter($alias) { if (!array_key_exists($alias, $this->formatters)) { - throw new \RuntimeException("The formatter with alias $alias is not known."); + throw new RuntimeException("The formatter with alias {$alias} is not known."); } - + return $this->formatters[$alias]; } - + + /** + * get the formatter alias from the form export data. + * + * @param array $data the data from the export form + * @string the formatter alias|null + */ + public function getFormatterAlias(array $data) + { + if (array_key_exists(ExportType::PICK_FORMATTER_KEY, $data)) { + return $data[ExportType::PICK_FORMATTER_KEY]['alias']; + } + + return null; + } + /** * Get all formatters which supports one of the given types. - * - * - * @param array $types - * @return \Generator + * + * @return Generator */ public function getFormattersByTypes(array $types) { @@ -340,419 +482,277 @@ class ExportManager } } } - - - /** - * Return a \Generator containing filter which support type. If `$centers` is - * not null, restrict the given filters to the center the user have access to. - * - * if $centers is null, the function will returns all filters where the user - * has access in every centers he can reach (if the user can use the filter F in - * center A, but not in center B, the filter F will not be returned) - * - * @param \Chill\MainBundle\Entity\Center[] $centers the centers where the user have access to - * @return FilterInterface[] a \Generator that contains filters. The key is the filter's alias - */ - public function &getFiltersApplyingOn(ExportInterface $export, array $centers = null) - { - foreach ($this->filters as $alias => $filter) { - if (in_array($filter->applyOn(), $export->supportsModifiers()) - && $this->isGrantedForElement($filter, $export, $centers)) { - yield $alias => $filter; - } - } - } - - /** - * Return true if the current user has access to the ExportElement for every - * center, false if the user hasn't access to element for at least one center. - * - * @param \Chill\MainBundle\Export\ExportElementInterface $element - * @param ExportInterface|DirectExportInterface $export - * @param array|null $centers, if null, the function take into account all the reachables centers for the current user and the role given by element::requiredRole - * @return boolean - */ - public function isGrantedForElement(ExportElementInterface $element, ExportElementInterface $export = NULL, array $centers = null) - { - if ($element instanceof ExportInterface || $element instanceof DirectExportInterface) { - $role = $element->requiredRole(); - } elseif ($element instanceof ModifierInterface ) { - if (is_null($element->addRole())) { - if (is_null($export)) { - throw new \LogicException("The export should not be null: as the " - . "ModifierInstance element is not an export, we should " - . "be aware of the export to determine which role is required"); - } else { - $role = $export->requiredRole(); - } - } else { - $role = $element->addRole(); - } - } else { - throw new \LogicException("The element is not an ModifiersInterface or " - . "an ExportInterface."); - } - - if ($centers === null) { - $centers = $this->authorizationHelper->getReachableCenters($this->user, - $role); - } - - if (count($centers) === 0) { - return false; - } - - foreach($centers as $center) { - if ($this->authorizationChecker->isGranted($role->getRole(), $center) === false) { - //debugging - $this->logger->debug('user has no access to element', array( - 'method' => __METHOD__, - 'type' => get_class($element), - 'center' => $center->getName(), - 'role' => $role->getRole() - )); - - return false; - } - } - - return true; - } - - /** - * Return a \Generator containing aggregators supported by the given export - * - * @internal This class check the interface implemented by export, and, if ´ListInterface´ is used, return an empty array - * @return AggregatorInterface[] a \Generator that contains aggretagors. The key is the filter's alias - */ - public function &getAggregatorsApplyingOn(ExportInterface $export, array $centers = null) - { - if ($export instanceof ListInterface) { - - return; - } - - foreach ($this->aggregators as $alias => $aggregator) { - if (in_array($aggregator->applyOn(), $export->supportsModifiers()) && - $this->isGrantedForElement($aggregator, $export, $centers)) { - yield $alias => $aggregator; - } - } - } - - /** - * Generate a response which contains the requested data. - * - * @param string $exportAlias - * @param mixed[] $data - * @return Response - */ - public function generate($exportAlias, array $pickedCentersData, array $data, array $formatterData) - { - $export = $this->getExport($exportAlias); - //$qb = $this->em->createQueryBuilder(); - $centers = $this->getPickedCenters($pickedCentersData); - - if ($export instanceof DirectExportInterface) { - return $export->generate( - $this->buildCenterReachableScopes($centers, $export), - $data[ExportType::EXPORT_KEY] - ); - } - - $query = $export->initiateQuery( - $this->retrieveUsedModifiers($data), - $this->buildCenterReachableScopes($centers, $export), - $data[ExportType::EXPORT_KEY] - ); - - if ($query instanceof \Doctrine\ORM\NativeQuery) { - // throw an error if the export require other modifier, which is - // not allowed when the export return a `NativeQuery` - if (count($export->supportsModifiers()) > 0) { - throw new \LogicException("The export with alias `$exportAlias` return " - . "a `\Doctrine\ORM\NativeQuery` and supports modifiers, which is not " - . "allowed. Either the method `supportsModifiers` should return an empty " - . "array, or return a `Doctrine\ORM\QueryBuilder`"); - } - } elseif ($query instanceof QueryBuilder) { - //handle filters - $this->handleFilters($export, $query, $data[ExportType::FILTER_KEY], $centers); - //handle aggregators - $this->handleAggregators($export, $query, $data[ExportType::AGGREGATOR_KEY], $centers); - - $this->logger->debug('current query is '.$query->getDQL(), array( - 'class' => self::class, 'function' => __FUNCTION__ - )); - } else { - throw new \UnexpectedValueException("The method `intiateQuery` should return " - . "a `\Doctrine\ORM\NativeQuery` or a `Doctrine\ORM\QueryBuilder` " - . "object."); - } - - $result = $export->getResult($query, $data[ExportType::EXPORT_KEY]); - - if (!is_iterable($result)) { - throw new \UnexpectedValueException( - sprintf( - 'The result of the export should be an iterable, %s given', - gettype($result) - ) - ); - } - - /* @var $formatter FormatterInterface */ - $formatter = $this->getFormatter($this->getFormatterAlias($data)); - $filtersData = array(); - $aggregatorsData = array(); - - if ($query instanceof QueryBuilder) { - $aggregators = $this->retrieveUsedAggregators($data[ExportType::AGGREGATOR_KEY]); - - foreach($aggregators as $alias => $aggregator) { - $aggregatorsData[$alias] = $data[ExportType::AGGREGATOR_KEY][$alias]['form']; - } - } - - $filters = $this->retrieveUsedFilters($data[ExportType::FILTER_KEY]); - - foreach($filters as $alias => $filter) { - $filtersData[$alias] = $data[ExportType::FILTER_KEY][$alias]['form']; - } - - return $formatter->getResponse( - $result, - $formatterData, - $exportAlias, - $data[ExportType::EXPORT_KEY], - $filtersData, - $aggregatorsData); - } - - /** - * build the array required for defining centers and circles in the initiate - * queries of ExportElementsInterfaces - * - * @param \Chill\MainBundle\Entity\Center[] $centers - */ - private function buildCenterReachableScopes(array $centers, ExportElementInterface $element) { - $r = array(); - - foreach($centers as $center) { - $r[] = array( - 'center' => $center, - 'circles' => $this->authorizationHelper->getReachableScopes($this->user, - $element->requiredRole(), $center) - ); - } - - return $r; - } - - /** - * get the aggregators typse used in the form export data - * - * @param array $data the data from the export form - * @return string[] - */ - public function getUsedAggregatorsAliases(array $data) - { - $aggregators = $this->retrieveUsedAggregators($data[ExportType::AGGREGATOR_KEY]); - - return array_keys(iterator_to_array($aggregators)); - } - - /** - * get the formatter alias from the form export data - * - * @param array $data the data from the export form - * @string the formatter alias|null - */ - public function getFormatterAlias(array $data) - { - if (array_key_exists(ExportType::PICK_FORMATTER_KEY, $data)) { - return $data[ExportType::PICK_FORMATTER_KEY]['alias']; - } - - return null; - } - /** * Get the Center picked by the user for this export. The data are - * extracted from the PickCenterType data - * + * extracted from the PickCenterType data. + * * @param array $data the data from a PickCenterType + * * @return \Chill\MainBundle\Entity\Center[] the picked center */ public function getPickedCenters(array $data) { return $data; } - + /** - * parse the data to retrieve the used filters and aggregators - * - * @param mixed $data + * get the aggregators typse used in the form export data. + * + * @param array $data the data from the export form + * * @return string[] */ - private function retrieveUsedModifiers($data) + public function getUsedAggregatorsAliases(array $data) { - if ($data === null) { - return []; - } - - $usedTypes = array_merge( - $this->retrieveUsedFiltersType($data[ExportType::FILTER_KEY]), - $this->retrieveUsedAggregatorsType($data[ExportType::AGGREGATOR_KEY]) - ); - - $this->logger->debug('Required types are '.implode(', ', $usedTypes), - array('class' => self::class, 'function' => __FUNCTION__)); - - return array_unique($usedTypes); + $aggregators = $this->retrieveUsedAggregators($data[ExportType::AGGREGATOR_KEY]); + + return array_keys(iterator_to_array($aggregators)); } - + /** - * Retrieve the filter used in this export. - * - * @param mixed $data the data from the `filters` key of the ExportType - * @return array an array with types + * Return true if the current user has access to the ExportElement for every + * center, false if the user hasn't access to element for at least one center. + * + * @param \Chill\MainBundle\Export\ExportElementInterface $element + * @param DirectExportInterface|ExportInterface $export + * + * @return bool */ - private function retrieveUsedFiltersType($data) + public function isGrantedForElement(ExportElementInterface $element, ?ExportElementInterface $export = null, ?array $centers = null) { - if ($data === null) { - return []; - } - - $usedTypes = array(); - foreach($data as $alias => $filterData) { - if ($filterData['enabled'] == true){ - $filter = $this->getFilter($alias); - if (!in_array($filter->applyOn(), $usedTypes)) { - array_push($usedTypes, $filter->applyOn()); + if ($element instanceof ExportInterface || $element instanceof DirectExportInterface) { + $role = $element->requiredRole(); + } elseif ($element instanceof ModifierInterface) { + if (is_null($element->addRole())) { + if (is_null($export)) { + throw new LogicException('The export should not be null: as the ' + . 'ModifierInstance element is not an export, we should ' + . 'be aware of the export to determine which role is required'); } + $role = $export->requiredRole(); + } else { + $role = $element->addRole(); } + } else { + throw new LogicException('The element is not an ModifiersInterface or ' + . 'an ExportInterface.'); } - - return $usedTypes; - } - - /** - * - * @param mixed $data - * @return string[] - */ - private function retrieveUsedAggregatorsType($data) - { - if ($data === null) { - return []; - } - - $usedTypes = array(); - foreach($this->retrieveUsedAggregators($data) as $alias => $aggregator) { - if (!in_array($aggregator->applyOn(), $usedTypes)) { - array_push($usedTypes, $aggregator->applyOn()); - } - } - - return $usedTypes; - } - - /** - * - * @param mixed $data - * @return AggregatorInterface[] - */ - private function retrieveUsedAggregators($data) - { - if ($data === null) { - return []; - } - - foreach ($data as $alias => $aggregatorData) { - if ($aggregatorData['enabled'] === true){ - yield $alias => $this->getAggregator($alias); - } - } - } - - /** - * - * @param type $data the data from the filter key of the ExportType - */ - private function retrieveUsedFilters($data) - { - if ($data === null) { - return []; - } - - foreach ($data as $alias => $filterData) { - if ($filterData['enabled'] === true) { - yield $alias => $this->getFilter($alias); - } - } - } - - /** - * alter the query with selected filters. - * - * This function check the acl. - * - * @param ExportInterface $export - * @param QueryBuilder $qb - * @param mixed $data the data under the initial 'filters' data - * @param \Chill\MainBundle\Entity\Center[] $centers the picked centers - * @throw UnauthorizedHttpException if the user is not authorized - */ - private function handleFilters( - ExportInterface $export, - QueryBuilder $qb, - $data, - array $centers) - { - $filters = $this->retrieveUsedFilters($data); - - foreach($filters as $alias => $filter) { - if ($this->isGrantedForElement($filter, $export, $centers) === false) { - throw new UnauthorizedHttpException("You are not authorized to " - . "use the filter ".$filter->getTitle()); - } - - $formData = $data[$alias]; - - $this->logger->debug('alter query by filter '.$alias, array( - 'class' => self::class, 'function' => __FUNCTION__ - )); - $filter->alterQuery($qb, $formData['form']); + if (null === $centers) { + $centers = $this->authorizationHelper->getReachableCenters( + $this->user, + $role + ); } + + if (count($centers) === 0) { + return false; + } + + foreach ($centers as $center) { + if ($this->authorizationChecker->isGranted($role->getRole(), $center) === false) { + //debugging + $this->logger->debug('user has no access to element', [ + 'method' => __METHOD__, + 'type' => get_class($element), + 'center' => $center->getName(), + 'role' => $role->getRole(), + ]); + + return false; + } + } + + return true; } - + /** - * Alter the query with selected aggregators - * + * build the array required for defining centers and circles in the initiate + * queries of ExportElementsInterfaces. + * + * @param \Chill\MainBundle\Entity\Center[] $centers + */ + private function buildCenterReachableScopes(array $centers, ExportElementInterface $element) + { + $r = []; + + foreach ($centers as $center) { + $r[] = [ + 'center' => $center, + 'circles' => $this->authorizationHelper->getReachableScopes( + $this->user, + $element->requiredRole(), + $center + ), + ]; + } + + return $r; + } + + /** + * Alter the query with selected aggregators. + * * Check for acl. If an user is not authorized to see an aggregator, throw an * UnauthorizedException. - * - * @param ExportInterface $export - * @param QueryBuilder $qb + * * @param type $data - * @param \Chill\MainBundle\Entity\Center[] $centers the picked centers * @throw UnauthorizedHttpException if the user is not authorized */ private function handleAggregators( - ExportInterface $export, - QueryBuilder $qb, - $data, - array $center) - { + ExportInterface $export, + QueryBuilder $qb, + $data, + array $center + ) { $aggregators = $this->retrieveUsedAggregators($data); - + foreach ($aggregators as $alias => $aggregator) { $formData = $data[$alias]; $aggregator->alterQuery($qb, $formData['form']); } } - + + /** + * alter the query with selected filters. + * + * This function check the acl. + * + * @param mixed $data the data under the initial 'filters' data + * @param \Chill\MainBundle\Entity\Center[] $centers the picked centers + * @throw UnauthorizedHttpException if the user is not authorized + */ + private function handleFilters( + ExportInterface $export, + QueryBuilder $qb, + $data, + array $centers + ) { + $filters = $this->retrieveUsedFilters($data); + + foreach ($filters as $alias => $filter) { + if ($this->isGrantedForElement($filter, $export, $centers) === false) { + throw new UnauthorizedHttpException('You are not authorized to ' + . 'use the filter ' . $filter->getTitle()); + } + + $formData = $data[$alias]; + + $this->logger->debug('alter query by filter ' . $alias, [ + 'class' => self::class, 'function' => __FUNCTION__, + ]); + $filter->alterQuery($qb, $formData['form']); + } + } + + /** + * @param mixed $data + * + * @return AggregatorInterface[] + */ + private function retrieveUsedAggregators($data) + { + if (null === $data) { + return []; + } + + foreach ($data as $alias => $aggregatorData) { + if (true === $aggregatorData['enabled']) { + yield $alias => $this->getAggregator($alias); + } + } + } + + /** + * @param mixed $data + * + * @return string[] + */ + private function retrieveUsedAggregatorsType($data) + { + if (null === $data) { + return []; + } + + $usedTypes = []; + + foreach ($this->retrieveUsedAggregators($data) as $alias => $aggregator) { + if (!in_array($aggregator->applyOn(), $usedTypes)) { + array_push($usedTypes, $aggregator->applyOn()); + } + } + + return $usedTypes; + } + + /** + * @param type $data the data from the filter key of the ExportType + */ + private function retrieveUsedFilters($data) + { + if (null === $data) { + return []; + } + + foreach ($data as $alias => $filterData) { + if (true === $filterData['enabled']) { + yield $alias => $this->getFilter($alias); + } + } + } + + /** + * Retrieve the filter used in this export. + * + * @param mixed $data the data from the `filters` key of the ExportType + * + * @return array an array with types + */ + private function retrieveUsedFiltersType($data) + { + if (null === $data) { + return []; + } + + $usedTypes = []; + + foreach ($data as $alias => $filterData) { + if (true == $filterData['enabled']) { + $filter = $this->getFilter($alias); + + if (!in_array($filter->applyOn(), $usedTypes)) { + array_push($usedTypes, $filter->applyOn()); + } + } + } + + return $usedTypes; + } + + /** + * parse the data to retrieve the used filters and aggregators. + * + * @param mixed $data + * + * @return string[] + */ + private function retrieveUsedModifiers($data) + { + if (null === $data) { + return []; + } + + $usedTypes = array_merge( + $this->retrieveUsedFiltersType($data[ExportType::FILTER_KEY]), + $this->retrieveUsedAggregatorsType($data[ExportType::AGGREGATOR_KEY]) + ); + + $this->logger->debug( + 'Required types are ' . implode(', ', $usedTypes), + ['class' => self::class, 'function' => __FUNCTION__] + ); + + return array_unique($usedTypes); + } } diff --git a/src/Bundle/ChillMainBundle/Export/FilterInterface.php b/src/Bundle/ChillMainBundle/Export/FilterInterface.php index b644ae8a7..ac7c0c7dc 100644 --- a/src/Bundle/ChillMainBundle/Export/FilterInterface.php +++ b/src/Bundle/ChillMainBundle/Export/FilterInterface.php @@ -1,70 +1,55 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; - /** - * Interface for filters. - * - * Filter will filter result on the query initiated by Export. Most of the time, - * it will add a `WHERE` clause on this query. - * - * Filters should not add column in `SELECT` clause. - * + * Interface for filters. * - * @author Julien Fastré + * Filter will filter result on the query initiated by Export. Most of the time, + * it will add a `WHERE` clause on this query. + * + * Filters should not add column in `SELECT` clause. */ interface FilterInterface extends ModifierInterface { - - const STRING_FORMAT = 'string'; - + public const STRING_FORMAT = 'string'; + /** * Describe the filtering action. - * - * The description will be inserted in report to remains to the user the + * + * The description will be inserted in report to remains to the user the * filters applyied on this report. - * - * Should return a statement about the filtering action, like : - * "filtering by date: from xxxx-xx-xx to xxxx-xx-xx" or + * + * Should return a statement about the filtering action, like : + * "filtering by date: from xxxx-xx-xx to xxxx-xx-xx" or * "filtering by nationality: only Germany, France" - * + * * The format will be determined by the $format. Currently, only 'string' is - * supported, later some 'html' will be added. The filter should always + * supported, later some 'html' will be added. The filter should always * implement the 'string' format and fallback to it if other format are used. - * + * * If no i18n is necessery, or if the filter translate the string by himself, * this function should return a string. If the filter does not do any translation, - * the return parameter should be an array, where - * - * - the first element is the string, + * the return parameter should be an array, where + * + * - the first element is the string, * - and the second an array of parameters (may be an empty array) * - the 3rd the domain (optional) * - the 4th the locale (optional) - * + * * Example: `array('my string with %parameter%', ['%parameter%' => 'good news'], 'mydomain', 'mylocale')` - * + * * @param array $data * @param string $format the format - * @return string|array a string with the data or, if translatable, an array where first element is string, second elements is an array of arguments + * + * @return array|string a string with the data or, if translatable, an array where first element is string, second elements is an array of arguments */ public function describeAction($data, $format = 'string'); - } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php index e77556a43..31218c5a8 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVFormatter.php @@ -1,95 +1,69 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export\Formatter; -use Chill\MainBundle\Export\ExportInterface; -use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; -use Symfony\Component\Form\Extension\Core\Type\FormType; +use Chill\MainBundle\Export\FormatterInterface; +use LogicException; +use RuntimeException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Translation\TranslatorInterface; // command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff /** - * - * - * @author Julien Fastré * @deprecated this formatter is not used any more. */ class CSVFormatter implements FormatterInterface { - /** - * - * @var TranslatorInterface - */ - protected $translator; - - protected $result; - - protected $formatterData; - - protected $export; - protected $aggregators; - protected $exportData; - protected $aggregatorsData; - protected $filtersData; + protected $export; - protected $labels; + protected $exportData; /** - * * @var ExportManager */ protected $exportManager; + protected $filtersData; - public function __construct(TranslatorInterface $translator, - ExportManager $manager) - { + protected $formatterData; + + protected $labels; + + protected $result; + + /** + * @var TranslatorInterface + */ + protected $translator; + + public function __construct( + TranslatorInterface $translator, + ExportManager $manager + ) { $this->translator = $translator; $this->exportManager = $manager; } - public function getType() - { - return 'tabular'; - } - - public function getName() - { - return 'Comma separated values (CSV)'; - } - /** - * * @uses appendAggregatorForm - * @param FormBuilderInterface $builder + * * @param type $exportAlias - * @param array $aggregatorAliases */ public function buildForm(FormBuilderInterface $builder, $exportAlias, array $aggregatorAliases) { @@ -97,58 +71,61 @@ class CSVFormatter implements FormatterInterface $nb = count($aggregatorAliases); foreach ($aggregators as $alias => $aggregator) { - $builderAggregator = $builder->create($alias, FormType::class, array( - 'label' => $aggregator->getTitle(), - 'block_name' => '_aggregator_placement_csv_formatter' - )); + $builderAggregator = $builder->create($alias, FormType::class, [ + 'label' => $aggregator->getTitle(), + 'block_name' => '_aggregator_placement_csv_formatter', + ]); $this->appendAggregatorForm($builderAggregator, $nb); $builder->add($builderAggregator); } } - /** - * append a form line by aggregator on the formatter form. - * - * This form allow to choose the aggregator position (row or column) and - * the ordering - * - * @param FormBuilderInterface $builder - * @param string $nbAggregators - */ - private function appendAggregatorForm(FormBuilderInterface $builder, $nbAggregators) + public function gatherFiltersDescriptions() { - $builder->add('order', ChoiceType::class, array( - 'choices' => array_combine( - range(1, $nbAggregators), - range(1, $nbAggregators) - ), - 'multiple' => false, - 'expanded' => false - )); + $descriptions = []; - $builder->add('position', ChoiceType::class, array( - 'choices' => array( - 'row' => 'r', - 'column' => 'c' - ), - 'multiple' => false, - 'expanded' => false - )); + foreach ($this->filtersData as $key => $filterData) { + $statement = $this->exportManager + ->getFilter($key) + ->describeAction($filterData); + + if (null === $statement) { + continue; + } + + if (is_array($statement)) { + $descriptions[] = $this->translator->trans( + $statement[0], + $statement[1], + $statement[2] ?? null, + $statement[3] ?? null + ); + } else { + $descriptions[] = $statement; + } + } + + return $descriptions; + } + + public function getName() + { + return 'Comma separated values (CSV)'; } public function getResponse( - $result, - $formatterData, - $exportAlias, - array $exportData, - array $filtersData, - array $aggregatorsData + $result, + $formatterData, + $exportAlias, + array $exportData, + array $filtersData, + array $aggregatorsData ) { $this->result = $result; $this->orderingHeaders($formatterData); $this->export = $this->exportManager->getExport($exportAlias); $this->aggregators = iterator_to_array($this->exportManager - ->getAggregators(array_keys($aggregatorsData))); + ->getAggregators(array_keys($aggregatorsData))); $this->exportData = $exportData; $this->aggregatorsData = $aggregatorsData; $this->labels = $this->gatherLabels(); @@ -164,24 +141,72 @@ class CSVFormatter implements FormatterInterface return $response; } - /** - * ordering aggregators, preserving key association. - * - * This function do not mind about position. - * - * If two aggregators have the same order, the second given will be placed - * after. This is not significant for the first ordering. - * - * @param type $formatterData - * @return type - */ - protected function orderingHeaders($formatterData) + public function getType() { - $this->formatterData = $formatterData; - uasort($this->formatterData, function($a, $b) { + return 'tabular'; + } - return ($a['order'] <= $b['order'] ? -1 : 1); - }); + protected function gatherLabels() + { + return array_merge( + $this->gatherLabelsFromAggregators(), + $this->gatherLabelsFromExport() + ); + } + + protected function gatherLabelsFromAggregators() + { + $labels = []; + /* @var $aggretator \Chill\MainBundle\Export\AggregatorInterface */ + foreach ($this->aggregators as $alias => $aggregator) { + $keys = $aggregator->getQueryKeys($this->aggregatorsData[$alias]); + + // gather data in an array + foreach ($keys as $key) { + $values = array_map(function ($row) use ($key, $alias) { + if (!array_key_exists($key, $row)) { + throw new LogicException("the key '" . $key . "' is declared by " + . "the aggregator with alias '" . $alias . "' but is not " + . 'present in results'); + } + + return $row[$key]; + }, $this->result); + $labels[$key] = $aggregator->getLabels( + $key, + array_unique($values), + $this->aggregatorsData[$alias] + ); + } + } + + return $labels; + } + + protected function gatherLabelsFromExport() + { + $labels = []; + $export = $this->export; + $keys = $this->export->getQueryKeys($this->exportData); + + foreach ($keys as $key) { + $values = array_map(function ($row) use ($key, $export) { + if (!array_key_exists($key, $row)) { + throw new LogicException("the key '" . $key . "' is declared by " + . "the export with title '" . $export->getTitle() . "' but is not " + . 'present in results'); + } + + return $row[$key]; + }, $this->result); + $labels[$key] = $this->export->getLabels( + $key, + array_unique($values), + $this->exportData + ); + } + + return $labels; } protected function generateContent() @@ -191,18 +216,20 @@ class CSVFormatter implements FormatterInterface $resultsKeysNb = count($this->export->getQueryKeys($this->exportData)); $results = $this->getOrderedResults(); /* @var $columnHeaders string[] the column headers associations */ - $columnHeaders = array(); + $columnHeaders = []; /* @var $data string[] the data of the csv file */ - $contentData = array(); - $content = array(); + $contentData = []; + $content = []; - function findColumnPosition(&$columnHeaders, $columnToFind) { + function findColumnPosition(&$columnHeaders, $columnToFind) + { $i = 0; - foreach($columnHeaders as $set) { + + foreach ($columnHeaders as $set) { if ($set === $columnToFind) { return $i; } - $i++; + ++$i; } //we didn't find it, adding the column @@ -215,16 +242,16 @@ class CSVFormatter implements FormatterInterface $output = fopen('php://output', 'w'); //title - fputcsv($output, array($this->translator->trans($this->export->getTitle()))); + fputcsv($output, [$this->translator->trans($this->export->getTitle())]); //blank line - fputcsv($output, array("")); + fputcsv($output, ['']); // add filtering description - foreach($this->gatherFiltersDescriptions() as $desc) { - fputcsv($output, array($desc)); + foreach ($this->gatherFiltersDescriptions() as $desc) { + fputcsv($output, [$desc]); } // blank line - fputcsv($output, array("")); + fputcsv($output, ['']); // iterate on result to : 1. populate row headers, 2. populate column headers, 3. add result foreach ($results as $row) { @@ -247,41 +274,42 @@ class CSVFormatter implements FormatterInterface $columnPosition = findColumnPosition($columnHeaders, $columns); //fill with blank at the position given by the columnPosition + nbRowHeaders - for ($i=0; $i < $columnPosition; $i++) { + for ($i = 0; $i < $columnPosition; ++$i) { if (!isset($line[$rowKeysNb + $i])) { - $line[$rowKeysNb + $i] = ""; + $line[$rowKeysNb + $i] = ''; } } - $resultData = array_slice($row, $resultsKeysNb*-1); - foreach($resultData as $data) { + $resultData = array_slice($row, $resultsKeysNb * -1); + + foreach ($resultData as $data) { $line[] = $data; } - } // we add the last line $contentData[] = $line; //column title headers - for ($i=0; $i < $columnKeysNb; $i++) { + for ($i = 0; $i < $columnKeysNb; ++$i) { $line = array_fill(0, $rowKeysNb, ''); - foreach($columnHeaders as $set) { + foreach ($columnHeaders as $set) { $line[] = $set[$i]; } $content[] = $line; } - //row title headers - $headerLine = array(); - foreach($this->getRowHeaders() as $headerKey) { + $headerLine = []; + + foreach ($this->getRowHeaders() as $headerKey) { $headerLine[] = array_key_exists('_header', $this->labels[$headerKey]) ? $this->labels[$headerKey]['_header'] : ''; } - foreach($this->export->getQueryKeys($this->exportData) as $key) { + + foreach ($this->export->getQueryKeys($this->exportData) as $key) { $headerLine[] = array_key_exists('_header', $this->labels[$key]) ? $this->labels[$key]['_header'] : ''; } @@ -289,10 +317,11 @@ class CSVFormatter implements FormatterInterface unset($headerLine); //free memory //generate CSV - foreach($content as $line) { + foreach ($content as $line) { fputcsv($output, $line); } - foreach($contentData as $line) { + + foreach ($contentData as $line) { fputcsv($output, $line); } @@ -302,10 +331,68 @@ class CSVFormatter implements FormatterInterface return $text; } + protected function getColumnHeaders() + { + return $this->getPositionnalHeaders('c'); + } + + protected function getRowHeaders() + { + return $this->getPositionnalHeaders('r'); + } + + /** + * ordering aggregators, preserving key association. + * + * This function do not mind about position. + * + * If two aggregators have the same order, the second given will be placed + * after. This is not significant for the first ordering. + * + * @param type $formatterData + * + * @return type + */ + protected function orderingHeaders($formatterData) + { + $this->formatterData = $formatterData; + uasort($this->formatterData, function ($a, $b) { + return $a['order'] <= $b['order'] ? -1 : 1; + }); + } + + /** + * append a form line by aggregator on the formatter form. + * + * This form allow to choose the aggregator position (row or column) and + * the ordering + * + * @param string $nbAggregators + */ + private function appendAggregatorForm(FormBuilderInterface $builder, $nbAggregators) + { + $builder->add('order', ChoiceType::class, [ + 'choices' => array_combine( + range(1, $nbAggregators), + range(1, $nbAggregators) + ), + 'multiple' => false, + 'expanded' => false, + ]); + + $builder->add('position', ChoiceType::class, [ + 'choices' => [ + 'row' => 'r', + 'column' => 'c', + ], + 'multiple' => false, + 'expanded' => false, + ]); + } private function getOrderedResults() { - $r = array(); + $r = []; $results = $this->result; $labels = $this->labels; $rowKeys = $this->getRowHeaders(); @@ -314,9 +401,9 @@ class CSVFormatter implements FormatterInterface $headers = array_merge($rowKeys, $columnKeys); foreach ($results as $row) { - $line = array(); - foreach ($headers as $key) { + $line = []; + foreach ($headers as $key) { $line[] = call_user_func($labels[$key], $row[$key]); } @@ -333,31 +420,22 @@ class CSVFormatter implements FormatterInterface return $r; } - - protected function getRowHeaders() - { - return $this->getPositionnalHeaders('r'); - } - - protected function getColumnHeaders() - { - return $this->getPositionnalHeaders('c'); - } - /** - * * @param string $position may be 'c' (column) or 'r' (row) + * + * @throws RuntimeException + * * @return string[] - * @throws \RuntimeException */ private function getPositionnalHeaders($position) { - $headers = array(); - foreach($this->formatterData as $alias => $data) { + $headers = []; + + foreach ($this->formatterData as $alias => $data) { if (!array_key_exists($alias, $this->aggregatorsData)) { - throw new \RuntimeException("the formatter wants to use the " - . "aggregator with alias $alias, but the export do not " - . "contains data about it"); + throw new RuntimeException('the formatter wants to use the ' + . "aggregator with alias {$alias}, but the export do not " + . 'contains data about it'); } $aggregator = $this->aggregators[$alias]; @@ -369,95 +447,4 @@ class CSVFormatter implements FormatterInterface return $headers; } - - /** - * - * @param mixed $result - * @param \Chill\MainBundle\Export\AggregatorInterface[] $aggregators - */ - protected function gatherLabels() - { - return array_merge( - $this->gatherLabelsFromAggregators(), - $this->gatherLabelsFromExport() - ); - } - - protected function gatherLabelsFromAggregators() - { - $labels = array(); - /* @var $aggretator \Chill\MainBundle\Export\AggregatorInterface */ - foreach ($this->aggregators as $alias => $aggregator) { - $keys = $aggregator->getQueryKeys($this->aggregatorsData[$alias]); - - // gather data in an array - foreach($keys as $key) { - $values = array_map(function($row) use ($key, $alias) { - if (!array_key_exists($key, $row)) { - throw new \LogicException("the key '".$key."' is declared by " - . "the aggregator with alias '".$alias."' but is not " - . "present in results"); - } - - return $row[$key]; - }, $this->result); - $labels[$key] = $aggregator->getLabels($key, array_unique($values), - $this->aggregatorsData[$alias]); - } - } - - return $labels; - } - - protected function gatherLabelsFromExport() - { - $labels = array(); - $export = $this->export; - $keys = $this->export->getQueryKeys($this->exportData); - - foreach($keys as $key) { - $values = array_map(function($row) use ($key, $export) { - if (!array_key_exists($key, $row)) { - throw new \LogicException("the key '".$key."' is declared by " - . "the export with title '".$export->getTitle()."' but is not " - . "present in results"); - } - - return $row[$key]; - }, $this->result); - $labels[$key] = $this->export->getLabels($key, array_unique($values), - $this->exportData); - } - - return $labels; - } - - public function gatherFiltersDescriptions() - { - $descriptions = array(); - - foreach($this->filtersData as $key => $filterData) { - - $statement = $this->exportManager - ->getFilter($key) - ->describeAction($filterData); - - if ($statement === null) { - continue; - } - - if (is_array($statement)) { - $descriptions[] = $this->translator->trans( - $statement[0], - $statement[1], - isset($statement[2]) ? $statement[2] : null, - isset($statement[3]) ? $statement[3] : null); - } else { - $descriptions[] = $statement; - } - } - - return $descriptions; - } - } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php index b3d004819..0f1476802 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVListFormatter.php @@ -1,68 +1,59 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export\Formatter; -use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Export\FormatterInterface; +use LogicException; +use OutOfBoundsException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Translation\TranslatorInterface; + +use function array_key_exists; +use function array_keys; +use function array_map; +use function implode; // command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff /** - * Create a CSV List for the export - * - * @author Champs-Libres + * Create a CSV List for the export. */ class CSVListFormatter implements FormatterInterface { - + protected $exportAlias; + + protected $exportData; + /** - * This variable cache the labels internally - * - * @var string[] - */ - protected $labelsCache = null; - - protected $result = null; - - protected $exportAlias = null; - - protected $exportData = null; - - protected $formatterData = null; - - /** - * * @var ExportManager */ protected $exportManager; - + + protected $formatterData; + /** + * This variable cache the labels internally. * + * @var string[] + */ + protected $labelsCache; + + protected $result; + + /** * @var TranslatorInterface */ protected $translator; - public function __construct(TranslatorInterface $translatorInterface, ExportManager $exportManager) { @@ -70,152 +61,130 @@ class CSVListFormatter implements FormatterInterface $this->exportManager = $exportManager; } - - public function getType() - { - return FormatterInterface::TYPE_LIST; + /** + * build a form, which will be used to collect data required for the execution + * of this formatter. + * + * @uses appendAggregatorForm + * + * @param type $exportAlias + */ + public function buildForm( + FormBuilderInterface $builder, + $exportAlias, + array $aggregatorAliases + ) { + $builder->add('numerotation', ChoiceType::class, [ + 'choices' => [ + 'yes' => true, + 'no' => false, + ], + 'expanded' => true, + 'multiple' => false, + 'label' => 'Add a number on first column', + 'data' => true, + ]); } - + public function getName() { return 'CSV vertical list'; } - + /** - * build a form, which will be used to collect data required for the execution - * of this formatter. - * - * @uses appendAggregatorForm - * @param FormBuilderInterface $builder - * @param type $exportAlias - * @param array $aggregatorAliases - */ - public function buildForm( - FormBuilderInterface $builder, - $exportAlias, - array $aggregatorAliases - ){ - $builder->add('numerotation', ChoiceType::class, array( - 'choices' => array( - 'yes' => true, - 'no' => false - ), - 'expanded' => true, - 'multiple' => false, - 'label' => "Add a number on first column", - 'data' => true - )); - } - - /** - * Generate a response from the data collected on differents ExportElementInterface - * + * Generate a response from the data collected on differents ExportElementInterface. + * * @param mixed[] $result The result, as given by the ExportInterface * @param mixed[] $formatterData collected from the current form * @param string $exportAlias the id of the current export * @param array $filtersData an array containing the filters data. The key are the filters id, and the value are the data * @param array $aggregatorsData an array containing the aggregators data. The key are the filters id, and the value are the data + * * @return \Symfony\Component\HttpFoundation\Response The response to be shown */ public function getResponse( - $result, - $formatterData, - $exportAlias, - array $exportData, - array $filtersData, + $result, + $formatterData, + $exportAlias, + array $exportData, + array $filtersData, array $aggregatorsData ) { $this->result = $result; $this->exportAlias = $exportAlias; $this->exportData = $exportData; $this->formatterData = $formatterData; - + $output = fopen('php://output', 'w'); - + $this->prepareHeaders($output); - + $i = 1; + foreach ($result as $row) { - $line = array(); - - if ($this->formatterData['numerotation'] === true) { + $line = []; + + if (true === $this->formatterData['numerotation']) { $line[] = $i; } - + foreach ($row as $key => $value) { $line[] = $this->getLabel($key, $value); } - + fputcsv($output, $line); - - $i++; + + ++$i; } - + $csvContent = stream_get_contents($output); fclose($output); - + $response = new Response(); $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/csv; charset=utf-8'); //$response->headers->set('Content-Disposition','attachment; filename="export.csv"'); $response->setContent($csvContent); - + return $response; } - - /** - * add the headers to the csv file - * - * @param resource $output - */ - protected function prepareHeaders($output) + + public function getType() { - $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); - // we want to keep the order of the first row. So we will iterate on the first row of the results - $first_row = count($this->result) > 0 ? $this->result[0] : array(); - $header_line = array(); - - if ($this->formatterData['numerotation'] === true) { - $header_line[] = $this->translator->trans('Number'); - } - - foreach ($first_row as $key => $value) { - $header_line[] = $this->translator->trans( - $this->getLabel($key, '_header')); - } - - if (count($header_line) > 0) { - fputcsv($output, $header_line); - } + return FormatterInterface::TYPE_LIST; } - + /** - * Give the label corresponding to the given key and value. - * + * Give the label corresponding to the given key and value. + * * @param string $key * @param string $value + * + * @throws LogicException if the label is not found + * * @return string - * @throws \LogicException if the label is not found */ protected function getLabel($key, $value) { - - if ($this->labelsCache === null) { + if (null === $this->labelsCache) { $this->prepareCacheLabels(); } - - if (!\array_key_exists($key, $this->labelsCache)){ - throw new \OutOfBoundsException(sprintf("The key \"%s\" " - . "is not present in the list of keys handled by " - . "this query. Check your `getKeys` and `getLabels` " - . "methods. Available keys are %s.", $key, - \implode(", ", \array_keys($this->labelsCache)))); + + if (!array_key_exists($key, $this->labelsCache)) { + throw new OutOfBoundsException(sprintf( + 'The key "%s" ' + . 'is not present in the list of keys handled by ' + . 'this query. Check your `getKeys` and `getLabels` ' + . 'methods. Available keys are %s.', + $key, + implode(', ', array_keys($this->labelsCache)) + )); } - + return $this->labelsCache[$key]($value); } - + /** * Prepare the label cache which will be used by getLabel. This function * should be called only once in the generation lifecycle. @@ -224,14 +193,41 @@ class CSVListFormatter implements FormatterInterface { $export = $this->exportManager->getExport($this->exportAlias); $keys = $export->getQueryKeys($this->exportData); - - foreach($keys as $key) { + + foreach ($keys as $key) { // get an array with all values for this key if possible - $values = \array_map(function ($v) use ($key) { return $v[$key]; }, $this->result); + $values = array_map(function ($v) use ($key) { + return $v[$key]; + }, $this->result); // store the label in the labelsCache property $this->labelsCache[$key] = $export->getLabels($key, $values, $this->exportData); } } - - + + /** + * add the headers to the csv file. + * + * @param resource $output + */ + protected function prepareHeaders($output) + { + $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); + // we want to keep the order of the first row. So we will iterate on the first row of the results + $first_row = count($this->result) > 0 ? $this->result[0] : []; + $header_line = []; + + if (true === $this->formatterData['numerotation']) { + $header_line[] = $this->translator->trans('Number'); + } + + foreach ($first_row as $key => $value) { + $header_line[] = $this->translator->trans( + $this->getLabel($key, '_header') + ); + } + + if (count($header_line) > 0) { + fputcsv($output, $header_line); + } + } } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php index 7d3087752..187904e6f 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/CSVPivotedListFormatter.php @@ -1,126 +1,107 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export\Formatter; -use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Export\FormatterInterface; +use LogicException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Translation\TranslatorInterface; + +use function array_map; /** - * Create a CSV List for the export where the header are printed on the + * Create a CSV List for the export where the header are printed on the * first column, and the result goes from left to right. - * - * @author Champs-Libres */ class CSVPivotedListFormatter implements FormatterInterface { - + protected $exportAlias; + + protected $exportData; + /** - * This variable cache the labels internally - * - * @var string[] - */ - protected $labelsCache = null; - - protected $result = null; - - protected $exportAlias = null; - - protected $exportData = null; - - protected $formatterData = null; - - /** - * * @var ExportManager */ protected $exportManager; - + + protected $formatterData; + /** + * This variable cache the labels internally. * + * @var string[] + */ + protected $labelsCache; + + protected $result; + + /** * @var TranslatorInterface */ protected $translator; - - public function __construct(TranslatorInterface $translatorInterface, ExportManager $exportManager) { $this->translator = $translatorInterface; $this->exportManager = $exportManager; } - - public function getType() - { - return FormatterInterface::TYPE_LIST; + + /** + * build a form, which will be used to collect data required for the execution + * of this formatter. + * + * @uses appendAggregatorForm + * + * @param type $exportAlias + */ + public function buildForm( + FormBuilderInterface $builder, + $exportAlias, + array $aggregatorAliases + ) { + $builder->add('numerotation', ChoiceType::class, [ + 'choices' => [ + 'yes' => true, + 'no' => false, + ], + 'expanded' => true, + 'multiple' => false, + 'label' => 'Add a number on first column', + 'data' => true, + ]); } - + public function getName() { return 'CSV horizontal list'; } - + /** - * build a form, which will be used to collect data required for the execution - * of this formatter. - * - * @uses appendAggregatorForm - * @param FormBuilderInterface $builder - * @param type $exportAlias - * @param array $aggregatorAliases - */ - public function buildForm( - FormBuilderInterface $builder, - $exportAlias, - array $aggregatorAliases - ){ - $builder->add('numerotation', ChoiceType::class, array( - 'choices' => array( - 'yes' => true, - 'no' => false - ), - 'expanded' => true, - 'multiple' => false, - 'label' => "Add a number on first column", - 'data' => true - )); - } - - /** - * Generate a response from the data collected on differents ExportElementInterface - * + * Generate a response from the data collected on differents ExportElementInterface. + * * @param mixed[] $result The result, as given by the ExportInterface * @param mixed[] $formatterData collected from the current form * @param string $exportAlias the id of the current export * @param array $filtersData an array containing the filters data. The key are the filters id, and the value are the data * @param array $aggregatorsData an array containing the aggregators data. The key are the filters id, and the value are the data + * * @return \Symfony\Component\HttpFoundation\Response The response to be shown */ public function getResponse( - $result, - $formatterData, - $exportAlias, - array $exportData, + $result, + $formatterData, + $exportAlias, + array $exportData, array $filtersData, array $aggregatorsData ) { @@ -128,85 +109,70 @@ class CSVPivotedListFormatter implements FormatterInterface $this->exportAlias = $exportAlias; $this->exportData = $exportData; $this->formatterData = $formatterData; - + $output = fopen('php://output', 'w'); - + $i = 1; - $lines = array(); + $lines = []; $this->prepareHeaders($lines); - + foreach ($result as $row) { $j = 0; - - if ($this->formatterData['numerotation'] === true) { + + if (true === $this->formatterData['numerotation']) { $lines[$j][] = $i; - $j++; + ++$j; } - + foreach ($row as $key => $value) { $lines[$j][] = $this->getLabel($key, $value); - $j++; + ++$j; } - $i++; + ++$i; } - + //adding the lines to the csv output - foreach($lines as $line) { + foreach ($lines as $line) { fputcsv($output, $line); } - + $csvContent = stream_get_contents($output); fclose($output); - + $response = new Response(); $response->setStatusCode(200); $response->headers->set('Content-Type', 'text/csv; charset=utf-8'); - $response->headers->set('Content-Disposition','attachment; filename="export.csv"'); + $response->headers->set('Content-Disposition', 'attachment; filename="export.csv"'); $response->setContent($csvContent); - + return $response; } - - /** - * add the headers to lines array - * - * @param array $lines the lines where the header will be added - */ - protected function prepareHeaders(array &$lines) + + public function getType() { - $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); - // we want to keep the order of the first row. So we will iterate on the first row of the results - $first_row = count($this->result) > 0 ? $this->result[0] : array(); - $header_line = array(); - - if ($this->formatterData['numerotation'] === true) { - $lines[] = array($this->translator->trans('Number')); - } - - foreach ($first_row as $key => $value) { - $lines[] = array($this->getLabel($key, '_header')); - } + return FormatterInterface::TYPE_LIST; } - + /** - * Give the label corresponding to the given key and value. - * + * Give the label corresponding to the given key and value. + * * @param string $key * @param string $value + * + * @throws LogicException if the label is not found + * * @return string - * @throws \LogicException if the label is not found */ protected function getLabel($key, $value) { - - if ($this->labelsCache === null) { + if (null === $this->labelsCache) { $this->prepareCacheLabels(); } - + return $this->labelsCache[$key]($value); } - + /** * Prepare the label cache which will be used by getLabel. This function * should be called only once in the generation lifecycle. @@ -215,14 +181,35 @@ class CSVPivotedListFormatter implements FormatterInterface { $export = $this->exportManager->getExport($this->exportAlias); $keys = $export->getQueryKeys($this->exportData); - - foreach($keys as $key) { + + foreach ($keys as $key) { // get an array with all values for this key if possible - $values = \array_map(function ($v) use ($key) { return $v[$key]; }, $this->result); + $values = array_map(function ($v) use ($key) { + return $v[$key]; + }, $this->result); // store the label in the labelsCache property $this->labelsCache[$key] = $export->getLabels($key, $values, $this->exportData); } } - - + + /** + * add the headers to lines array. + * + * @param array $lines the lines where the header will be added + */ + protected function prepareHeaders(array &$lines) + { + $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); + // we want to keep the order of the first row. So we will iterate on the first row of the results + $first_row = count($this->result) > 0 ? $this->result[0] : []; + $header_line = []; + + if (true === $this->formatterData['numerotation']) { + $lines[] = [$this->translator->trans('Number')]; + } + + foreach ($first_row as $key => $value) { + $lines[] = [$this->getLabel($key, '_header')]; + } + } } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php index d14ecb9ad..255387ef9 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadSheetFormatter.php @@ -1,96 +1,39 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Export\Formatter; - -use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Chill\MainBundle\Export\ExportManager; -use Symfony\Component\Form\Extension\Core\Type\FormType; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; /** + * Chill is a software for social workers * - * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Export\Formatter; + +use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Export\FormatterInterface; +use LogicException; +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Translation\TranslatorInterface; + +use function array_map; +use function array_merge; +use function array_multisort; +use function array_unique; +use function fopen; +use function stream_get_contents; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; + class SpreadSheetFormatter implements FormatterInterface { - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * - * @var ExportManager - */ - protected $exportManager; - - /** - * The result, as returned by the export - * - * replaced when `getResponse` is called. - * - * @var type - */ - protected $result; - - /** - * - * replaced when `getResponse` is called. - * - * @var type - */ - protected $formatterData; - - /** - * The export - * - * replaced when `getResponse` is called. - * - * @var \Chill\MainBundle\Export\ExportInterface - */ - protected $export; - - /** - * - * replaced when `getResponse` is called. - * - * @var type - */ - //protected $aggregators; - - /** - * array containing value of export form - * - * replaced when `getResponse` is called. - * - * @var array - */ - protected $exportData; - /** * an array where keys are the aggregators aliases and - * values are the data + * values are the data. * * replaced when `getResponse` is called. * @@ -99,7 +42,36 @@ class SpreadSheetFormatter implements FormatterInterface protected $aggregatorsData; /** + * The export. * + * replaced when `getResponse` is called. + * + * @var \Chill\MainBundle\Export\ExportInterface + */ + protected $export; + + /** + * replaced when `getResponse` is called. + * + * @var type + */ + //protected $aggregators; + + /** + * array containing value of export form. + * + * replaced when `getResponse` is called. + * + * @var array + */ + protected $exportData; + + /** + * @var ExportManager + */ + protected $exportManager; + + /** * replaced when `getResponse` is called. * * @var array @@ -107,7 +79,22 @@ class SpreadSheetFormatter implements FormatterInterface protected $filtersData; /** + * replaced when `getResponse` is called. * + * @var type + */ + protected $formatterData; + + /** + * The result, as returned by the export. + * + * replaced when `getResponse` is called. + * + * @var type + */ + protected $result; + + /** * replaced when `getResponse` is called. * * @var array @@ -115,12 +102,17 @@ class SpreadSheetFormatter implements FormatterInterface //protected $labels; /** - * temporary file to store spreadsheet + * temporary file to store spreadsheet. * * @var string */ protected $tempfile; + /** + * @var TranslatorInterface + */ + protected $translator; + /** * cache for displayable result. * @@ -137,7 +129,7 @@ class SpreadSheetFormatter implements FormatterInterface /** * Whethe `cacheDisplayableResult` is initialized or not. * - * @var boolean + * @var bool */ private $cacheDisplayableResultIsInitialized = false; @@ -147,58 +139,35 @@ class SpreadSheetFormatter implements FormatterInterface $this->exportManager = $exportManager; } - public function buildForm( FormBuilderInterface $builder, $exportAlias, array $aggregatorAliases ) { // choosing between formats - $builder->add('format', ChoiceType::class, array( - 'choices' => array( + $builder->add('format', ChoiceType::class, [ + 'choices' => [ 'OpenDocument Format (.ods) (LibreOffice, ...)' => 'ods', 'Microsoft Excel 2007-2013 XML (.xlsx) (Microsoft Excel, LibreOffice)' => 'xlsx', - 'Comma separated values (.csv)' => 'csv' - ), - 'placeholder' => 'Choose the format' - )); + 'Comma separated values (.csv)' => 'csv', + ], + 'placeholder' => 'Choose the format', + ]); // ordering aggregators $aggregators = $this->exportManager->getAggregators($aggregatorAliases); $nb = count($aggregatorAliases); foreach ($aggregators as $alias => $aggregator) { - $builderAggregator = $builder->create($alias, FormType::class, array( - 'label' => $aggregator->getTitle(), - 'block_name' => '_aggregator_placement_spreadsheet_formatter' - )); + $builderAggregator = $builder->create($alias, FormType::class, [ + 'label' => $aggregator->getTitle(), + 'block_name' => '_aggregator_placement_spreadsheet_formatter', + ]); $this->appendAggregatorForm($builderAggregator, $nb); $builder->add($builderAggregator); } } - /** - * append a form line by aggregator on the formatter form. - * - * This form allow to choose the aggregator position (row or column) and - * the ordering - * - * @param FormBuilderInterface $builder - * @param string $nbAggregators - */ - private function appendAggregatorForm(FormBuilderInterface $builder, $nbAggregators) - { - $builder->add('order', ChoiceType::class, array( - 'choices' => array_combine( - range(1, $nbAggregators), - range(1, $nbAggregators) - ), - 'multiple' => false, - 'expanded' => false - )); - - } - public function getName() { return 'SpreadSheet (xlsx, ods)'; @@ -221,69 +190,123 @@ class SpreadSheetFormatter implements FormatterInterface $this->aggregatorsData = $aggregatorsData; // reset cache - $this->cacheDisplayableResult = array(); + $this->cacheDisplayableResult = []; $this->cacheDisplayableResultIsInitialized = false; $response = new Response(); - $response->headers->set('Content-Type', - $this->getContentType($this->formatterData['format'])); + $response->headers->set( + 'Content-Type', + $this->getContentType($this->formatterData['format']) + ); - $this->tempfile = \tempnam(\sys_get_temp_dir(), ''); + $this->tempfile = tempnam(sys_get_temp_dir(), ''); $this->generatecontent(); - $f = \fopen($this->tempfile, 'r'); - $response->setContent(\stream_get_contents($f)); + $f = fopen($this->tempfile, 'r'); + $response->setContent(stream_get_contents($f)); fclose($f); // remove the temp file from disk - \unlink($this->tempfile); + unlink($this->tempfile); return $response; } - /** - * Generate the content and write it to php://temp - */ - protected function generateContent() + public function getType() { - list($spreadsheet, $worksheet) = $this->createSpreadsheet(); + return 'tabular'; + } - $this->addTitleToWorkSheet($worksheet); - $line = $this->addFiltersDescription($worksheet); + protected function addContentTable( + Worksheet $worksheet, + $sortedResults, + $line + ) { + $worksheet->fromArray( + $sortedResults, + null, + 'A' . $line + ); - // at this point, we are going to sort retsults for an easier manipulation - list($sortedResult, $exportKeys, $aggregatorKeys, $globalKeys) = - $this->sortResult(); - - $line = $this->addHeaders($worksheet, $globalKeys, $line); - - $line = $this->addContentTable($worksheet, $sortedResult, $line); - - switch ($this->formatterData['format']) - { - case 'ods': - $writer = \PhpOffice\PhpSpreadsheet\IOFactory - ::createWriter($spreadsheet, 'Ods'); - break; - case 'xlsx': - $writer = \PhpOffice\PhpSpreadsheet\IOFactory - ::createWriter($spreadsheet, 'Xlsx'); - break; - case 'csv': - $writer = \PhpOffice\PhpSpreadsheet\IOFactory - ::createWriter($spreadsheet, 'Csv'); - break; - default: - // this should not happen - // throw an exception to ensure that the error is catched - throw new \LogicException(); - } - - $writer->save($this->tempfile); + return $line + count($sortedResults) + 1; } /** - * Create a spreadsheet and a working worksheet + * Add filter description since line 3. + * + * return the line number after the last description + * + * @return int the line number after the last description + */ + protected function addFiltersDescription(Worksheet &$worksheet) + { + $line = 3; + + foreach ($this->filtersData as $alias => $data) { + $filter = $this->exportManager->getFilter($alias); + $description = $filter->describeAction($data, 'string'); + + if (is_array($description)) { + $description = $this->translator + ->trans( + $description[0], + $description[1] ?? [] + ); + } + + $worksheet->setCellValue('A' . $line, $description); + ++$line; + } + + return $line; + } + + /** + * add headers to worksheet. + * + * return the line number where the next content (i.e. result) should + * be appended. + * + * @param int $line + * + * @return int + */ + protected function addHeaders( + Worksheet &$worksheet, + array $globalKeys, + $line + ) { + // get the displayable form of headers + $displayables = []; + + foreach ($globalKeys as $key) { + $displayables[] = $this->translator->trans( + $this->getDisplayableResult($key, '_header') + ); + } + + // add headers on worksheet + $worksheet->fromArray( + $displayables, + null, + 'A' . $line + ); + + return $line + 1; + } + + /** + * Add the title to the worksheet and merge the cell containing + * the title. + */ + protected function addTitleToWorkSheet(Worksheet &$worksheet) + { + $worksheet->setCellValue('A1', $this->getTitle()); + $worksheet->mergeCells('A1:G1'); + } + + /** + * Create a spreadsheet and a working worksheet. * * @return array where 1st member is spreadsheet, 2nd is worksheet */ @@ -301,46 +324,179 @@ class SpreadSheetFormatter implements FormatterInterface } /** - * Add the title to the worksheet and merge the cell containing - * the title - * - * @param Worksheet $worksheet + * Generate the content and write it to php://temp. */ - protected function addTitleToWorkSheet(Worksheet &$worksheet) + protected function generateContent() { - $worksheet->setCellValue('A1', $this->getTitle()); - $worksheet->mergeCells('A1:G1'); + [$spreadsheet, $worksheet] = $this->createSpreadsheet(); + + $this->addTitleToWorkSheet($worksheet); + $line = $this->addFiltersDescription($worksheet); + + // at this point, we are going to sort retsults for an easier manipulation + [$sortedResult, $exportKeys, $aggregatorKeys, $globalKeys] = + $this->sortResult(); + + $line = $this->addHeaders($worksheet, $globalKeys, $line); + + $line = $this->addContentTable($worksheet, $sortedResult, $line); + + switch ($this->formatterData['format']) { + case 'ods': + $writer = \PhpOffice\PhpSpreadsheet\IOFactory + ::createWriter($spreadsheet, 'Ods'); + + break; + + case 'xlsx': + $writer = \PhpOffice\PhpSpreadsheet\IOFactory + ::createWriter($spreadsheet, 'Xlsx'); + + break; + + case 'csv': + $writer = \PhpOffice\PhpSpreadsheet\IOFactory + ::createWriter($spreadsheet, 'Csv'); + + break; + + default: + // this should not happen + // throw an exception to ensure that the error is catched + throw new LogicException(); + } + + $writer->save($this->tempfile); } /** - * Add filter description since line 3. + * get an array of aggregator keys. The keys are sorted as asked + * by user in the form. * - * return the line number after the last description - * - * @param Worksheet $worksheet - * @return int the line number after the last description + * @return string[] an array containing the keys of aggregators */ - protected function addFiltersDescription(Worksheet &$worksheet) + protected function getAggregatorKeysSorted() { - $line = 3; + // empty array for aggregators keys + $keys = []; + // this association between key and aggregator alias will be used + // during sorting + $aggregatorKeyAssociation = []; - foreach ($this->filtersData as $alias => $data) { - $filter = $this->exportManager->getFilter($alias); - $description = $filter->describeAction($data, 'string'); - - if (is_array($description)) { - $description = $this->translator - ->trans( - $description[0], - isset($description[1]) ? $description[1] : [] - ); + foreach ($this->aggregatorsData as $alias => $data) { + $aggregator = $this->exportManager->getAggregator($alias); + $aggregatorsKeys = $aggregator->getQueryKeys($data); + // append the keys from aggregator to the $keys existing array + $keys = array_merge($keys, $aggregatorsKeys); + // append the key with the alias, which will be use later for sorting + foreach ($aggregatorsKeys as $key) { + $aggregatorKeyAssociation[$key] = $alias; } - - $worksheet->setCellValue('A'.$line, $description); - $line ++; } - return $line; + // sort the result using the form + usort($keys, function ($a, $b) use ($aggregatorKeyAssociation) { + $A = $this->formatterData[$aggregatorKeyAssociation[$a]]['order']; + $B = $this->formatterData[$aggregatorKeyAssociation[$b]]['order']; + + if ($A === $B) { + return 0; + } + + if ($A > $B) { + return 1; + } + + return -1; + }); + + return $keys; + } + + protected function getContentType($format) + { + switch ($format) { + case 'csv': + return 'text/csv'; + + case 'ods': + return 'application/vnd.oasis.opendocument.spreadsheet'; + + case 'xlsx': + return 'application/vnd.openxmlformats-officedocument.' + . 'spreadsheetml.sheet'; + } + } + + /** + * Get the displayable result. + * + * @param string $key + * @param string $value + * + * @return string + */ + protected function getDisplayableResult($key, $value) + { + if (false === $this->cacheDisplayableResultIsInitialized) { + $this->initializeCache($key); + } + + return call_user_func($this->cacheDisplayableResult[$key], $value); + } + + protected function getTitle() + { + return $this->translator->trans($this->export->getTitle()); + } + + protected function initializeCache($key) + { + /* + * this function follows the following steps : + * + * 1. associate all keys used in result with their export element + * (export or aggregator) and data; + * 2. associate all keys used in result with all the possible values : + * this array will be necessary to call `getLabels` + * 3. store the `callable` in an associative array, in cache + */ + // 1. create an associative array with key and export / aggregator + $keysExportElementAssociation = []; + // keys for export + foreach ($this->export->getQueryKeys($this->exportData) as $key) { + $keysExportElementAssociation[$key] = [$this->export, + $this->exportData, ]; + } + // keys for aggregator + foreach ($this->aggregatorsData as $alias => $data) { + $aggregator = $this->exportManager->getAggregator($alias); + + foreach ($aggregator->getQueryKeys($data) as $key) { + $keysExportElementAssociation[$key] = [$aggregator, $data]; + } + } + + // 2. collect all the keys before iteration + $keys = array_keys($keysExportElementAssociation); + + $allValues = []; + // store all the values in an array + foreach ($this->result as $row) { + foreach ($keys as $key) { + $allValues[$key][] = $row[$key]; + } + } + + // 3. iterate on `keysExportElementAssociation` to store the callable + // in cache + foreach ($keysExportElementAssociation as $key => [$element, $data]) { + $this->cacheDisplayableResult[$key] = + $element->getLabels($key, array_unique($allValues[$key]), $data); + } + + // the cache is initialized ! + $this->cacheDisplayableResultIsInitialized = true; } /** @@ -348,8 +504,7 @@ class SpreadSheetFormatter implements FormatterInterface * - 0 => sorted results * - 1 => export keys * - 2 => aggregator keys - * - 3 => global keys (aggregator keys and export keys) - * + * - 3 => global keys (aggregator keys and export keys). * * Example, assuming that the result contains two aggregator keys : * @@ -378,7 +533,6 @@ class SpreadSheetFormatter implements FormatterInterface * array( 5, 6, 4 ) * ) * ``` - * */ protected function sortResult() { @@ -386,198 +540,40 @@ class SpreadSheetFormatter implements FormatterInterface $exportKeys = $this->export->getQueryKeys($this->exportData); $aggregatorKeys = $this->getAggregatorKeysSorted(); - $globalKeys = \array_merge($aggregatorKeys, $exportKeys); + $globalKeys = array_merge($aggregatorKeys, $exportKeys); - $sortedResult = \array_map(function ($row) use ($globalKeys) { - $newRow = array(); + $sortedResult = array_map(function ($row) use ($globalKeys) { + $newRow = []; - foreach ($globalKeys as $key) { - $newRow[] = $this->getDisplayableResult($key, $row[$key]); - } + foreach ($globalKeys as $key) { + $newRow[] = $this->getDisplayableResult($key, $row[$key]); + } - return $newRow; - }, $this->result); + return $newRow; + }, $this->result); - \array_multisort($sortedResult); + array_multisort($sortedResult); - return array($sortedResult, $exportKeys, $aggregatorKeys, $globalKeys); + return [$sortedResult, $exportKeys, $aggregatorKeys, $globalKeys]; } /** - * get an array of aggregator keys. The keys are sorted as asked - * by user in the form. + * append a form line by aggregator on the formatter form. * - * @return string[] an array containing the keys of aggregators + * This form allow to choose the aggregator position (row or column) and + * the ordering + * + * @param string $nbAggregators */ - protected function getAggregatorKeysSorted() + private function appendAggregatorForm(FormBuilderInterface $builder, $nbAggregators) { - // empty array for aggregators keys - $keys = array(); - // this association between key and aggregator alias will be used - // during sorting - $aggregatorKeyAssociation = array(); - - foreach ($this->aggregatorsData as $alias => $data) { - $aggregator = $this->exportManager->getAggregator($alias); - $aggregatorsKeys = $aggregator->getQueryKeys($data); - // append the keys from aggregator to the $keys existing array - $keys = \array_merge($keys, $aggregatorsKeys); - // append the key with the alias, which will be use later for sorting - foreach ($aggregatorsKeys as $key) { - $aggregatorKeyAssociation[$key] = $alias; - } - } - - // sort the result using the form - usort($keys, function ($a, $b) use ($aggregatorKeyAssociation) { - $A = $this->formatterData[$aggregatorKeyAssociation[$a]]['order']; - $B = $this->formatterData[$aggregatorKeyAssociation[$b]]['order']; - - if ($A === $B) { - return 0; - } elseif ($A > $B) { - return 1; - } else { - return -1; - } - - }); - - return $keys; - } - - /** - * add headers to worksheet - * - * return the line number where the next content (i.e. result) should - * be appended. - * - * @param Worksheet $worksheet - * @param array $aggregatorKeys - * @param array $exportKeys - * @param int $line - * @return int - */ - protected function addHeaders( - Worksheet &$worksheet, - array $globalKeys, - $line - ) { - // get the displayable form of headers - $displayables = array(); - foreach ($globalKeys as $key) { - $displayables[] = $this->translator->trans( - $this->getDisplayableResult($key, '_header') - ); - } - - // add headers on worksheet - $worksheet->fromArray( - $displayables, - NULL, - 'A'.$line); - - return $line + 1; - } - - protected function addContentTable(Worksheet $worksheet, - $sortedResults, - $line - ) { - $worksheet->fromArray( - $sortedResults, - NULL, - 'A'.$line); - - return $line + count($sortedResults) + 1; - } - - protected function getTitle() - { - return $this->translator->trans($this->export->getTitle()); - } - - /** - * Get the displayable result. - * - * @param string $key - * @param string $value - * @return string - */ - protected function getDisplayableResult($key, $value) - { - if ($this->cacheDisplayableResultIsInitialized === false) { - $this->initializeCache($key); - } - - return call_user_func($this->cacheDisplayableResult[$key], $value); - } - - protected function initializeCache($key) - { - /* - * this function follows the following steps : - * - * 1. associate all keys used in result with their export element - * (export or aggregator) and data; - * 2. associate all keys used in result with all the possible values : - * this array will be necessary to call `getLabels` - * 3. store the `callable` in an associative array, in cache - */ - // 1. create an associative array with key and export / aggregator - $keysExportElementAssociation = array(); - // keys for export - foreach ($this->export->getQueryKeys($this->exportData) as $key) { - $keysExportElementAssociation[$key] = [$this->export, - $this->exportData]; - } - // keys for aggregator - foreach ($this->aggregatorsData as $alias => $data) { - $aggregator = $this->exportManager->getAggregator($alias); - - foreach ($aggregator->getQueryKeys($data) as $key) { - $keysExportElementAssociation[$key] = [$aggregator, $data]; - } - } - - // 2. collect all the keys before iteration - $keys = array_keys($keysExportElementAssociation); - - $allValues = array(); - // store all the values in an array - foreach ($this->result as $row) { - foreach ($keys as $key) { - $allValues[$key][] = $row[$key]; - } - } - - // 3. iterate on `keysExportElementAssociation` to store the callable - // in cache - foreach ($keysExportElementAssociation as $key => list($element, $data)) { - $this->cacheDisplayableResult[$key] = - $element->getLabels($key, \array_unique($allValues[$key]), $data); - } - - // the cache is initialized ! - $this->cacheDisplayableResultIsInitialized = true; - } - - protected function getContentType($format) - { - switch ($format) - { - case 'csv': - return 'text/csv'; - case 'ods': - return 'application/vnd.oasis.opendocument.spreadsheet'; - case 'xlsx': - return 'application/vnd.openxmlformats-officedocument.' - . 'spreadsheetml.sheet'; - } - } - - public function getType() - { - return 'tabular'; + $builder->add('order', ChoiceType::class, [ + 'choices' => array_combine( + range(1, $nbAggregators), + range(1, $nbAggregators) + ), + 'multiple' => false, + 'expanded' => false, + ]); } } diff --git a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php index 221375f0b..381054e61 100644 --- a/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php +++ b/src/Bundle/ChillMainBundle/Export/Formatter/SpreadsheetListFormatter.php @@ -1,163 +1,158 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export\Formatter; -use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Export\FormatterInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Chill\MainBundle\Export\FormatterInterface; +use DateTimeInterface; +use LogicException; +use OutOfBoundsException; use PhpOffice\PhpSpreadsheet\Shared\Date; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Translation\TranslatorInterface; + +use function array_key_exists; +use function array_keys; +use function array_map; +use function fopen; +use function implode; +use function stream_get_contents; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; // command to get the report with curl : curl --user "center a_social:password" "http://localhost:8000/fr/exports/generate/count_person?export[filters][person_gender_filter][enabled]=&export[filters][person_nationality_filter][enabled]=&export[filters][person_nationality_filter][form][nationalities]=&export[aggregators][person_nationality_aggregator][order]=1&export[aggregators][person_nationality_aggregator][form][group_by_level]=country&export[submit]=&export[_token]=RHpjHl389GrK-bd6iY5NsEqrD5UKOTHH40QKE9J1edU" --globoff /** - * Create a CSV List for the export - * - * @author Champs-Libres + * Create a CSV List for the export. */ class SpreadsheetListFormatter implements FormatterInterface { + protected $exportAlias; + + protected $exportData; + /** - * This variable cache the labels internally - * - * @var string[] - */ - protected $labelsCache = null; - - protected $result = null; - - protected $exportAlias = null; - - protected $exportData = null; - - protected $formatterData = null; - - /** - * * @var ExportManager */ protected $exportManager; - + + protected $formatterData; + /** + * This variable cache the labels internally. * + * @var string[] + */ + protected $labelsCache; + + protected $result; + + /** * @var TranslatorInterface */ protected $translator; - - public function __construct(TranslatorInterface $translatorInterface, ExportManager $exportManager) { $this->translator = $translatorInterface; $this->exportManager = $exportManager; } - - public function getType() - { - return FormatterInterface::TYPE_LIST; - } - + /** * build a form, which will be used to collect data required for the execution * of this formatter. - * + * * @uses appendAggregatorForm - * @param FormBuilderInterface $builder + * * @param type $exportAlias - * @param array $aggregatorAliases */ public function buildForm( - FormBuilderInterface $builder, - $exportAlias, + FormBuilderInterface $builder, + $exportAlias, array $aggregatorAliases - ){ + ) { $builder - ->add('format', ChoiceType::class, array( - 'choices' => array( + ->add('format', ChoiceType::class, [ + 'choices' => [ 'OpenDocument Format (.ods) (LibreOffice, ...)' => 'ods', - 'Microsoft Excel 2007-2013 XML (.xlsx) (Microsoft Excel, LibreOffice)' => 'xlsx' - ), - 'placeholder' => 'Choose the format' - )) - ->add('numerotation', ChoiceType::class, array( - 'choices' => array( + 'Microsoft Excel 2007-2013 XML (.xlsx) (Microsoft Excel, LibreOffice)' => 'xlsx', + ], + 'placeholder' => 'Choose the format', + ]) + ->add('numerotation', ChoiceType::class, [ + 'choices' => [ 'yes' => true, - 'no' => false - ), + 'no' => false, + ], 'expanded' => true, 'multiple' => false, - 'label' => "Add a number on first column", - 'data' => true - )); + 'label' => 'Add a number on first column', + 'data' => true, + ]); } - + public function getName() { return 'Spreadsheet list formatter (.xlsx, .ods)'; } - + /** - * Generate a response from the data collected on differents ExportElementInterface - * + * Generate a response from the data collected on differents ExportElementInterface. + * * @param mixed[] $result The result, as given by the ExportInterface * @param mixed[] $formatterData collected from the current form * @param string $exportAlias the id of the current export * @param array $filtersData an array containing the filters data. The key are the filters id, and the value are the data * @param array $aggregatorsData an array containing the aggregators data. The key are the filters id, and the value are the data + * * @return \Symfony\Component\HttpFoundation\Response The response to be shown */ public function getResponse( - $result, - $formatterData, - $exportAlias, - array $exportData, - array $filtersData, + $result, + $formatterData, + $exportAlias, + array $exportData, + array $filtersData, array $aggregatorsData ) { $this->result = $result; $this->exportAlias = $exportAlias; $this->exportData = $exportData; $this->formatterData = $formatterData; - + $spreadsheet = new Spreadsheet(); $worksheet = $spreadsheet->getActiveSheet(); - + $this->prepareHeaders($worksheet); - + $i = 1; + foreach ($result as $row) { - $line = array(); - - if ($this->formatterData['numerotation'] === true) { - $worksheet->setCellValue('A'.($i+1), (string) $i); + $line = []; + + if (true === $this->formatterData['numerotation']) { + $worksheet->setCellValue('A' . ($i + 1), (string) $i); } - + $a = $this->formatterData['numerotation'] ? 'B' : 'A'; + foreach ($row as $key => $value) { - $row = $a.($i+1); - if ($value instanceof \DateTimeInterface) { + $row = $a . ($i + 1); + + if ($value instanceof DateTimeInterface) { $worksheet->setCellValue($row, Date::PHPToExcel($value)); $worksheet->getStyle($row) ->getNumberFormat() @@ -165,105 +160,93 @@ class SpreadsheetListFormatter implements FormatterInterface } else { $worksheet->setCellValue($row, $this->getLabel($key, $value)); } - $a ++; + ++$a; } - - $i++; + + ++$i; } - switch ($this->formatterData['format']) - { + switch ($this->formatterData['format']) { case 'ods': $writer = \PhpOffice\PhpSpreadsheet\IOFactory ::createWriter($spreadsheet, 'Ods'); - $contentType = "application/vnd.oasis.opendocument.spreadsheet"; + $contentType = 'application/vnd.oasis.opendocument.spreadsheet'; + break; + case 'xlsx': $writer = \PhpOffice\PhpSpreadsheet\IOFactory ::createWriter($spreadsheet, 'Xlsx'); $contentType = 'application/vnd.openxmlformats-officedocument.' . 'spreadsheetml.sheet'; + break; + case 'csv': $writer = \PhpOffice\PhpSpreadsheet\IOFactory ::createWriter($spreadsheet, 'Csv'); $contentType = 'text/csv'; + break; + default: // this should not happen // throw an exception to ensure that the error is catched - throw new \OutOfBoundsException("The format ".$this->formatterData['format']. - " is not supported"); + throw new OutOfBoundsException('The format ' . $this->formatterData['format'] . + ' is not supported'); } - + $response = new Response(); $response->headers->set('content-type', $contentType); - - $tempfile = \tempnam(\sys_get_temp_dir(), ''); + + $tempfile = tempnam(sys_get_temp_dir(), ''); $writer->save($tempfile); - - $f = \fopen($tempfile, 'r'); - $response->setContent(\stream_get_contents($f)); + + $f = fopen($tempfile, 'r'); + $response->setContent(stream_get_contents($f)); fclose($f); // remove the temp file from disk - \unlink($tempfile); - + unlink($tempfile); + return $response; } - - /** - * add the headers to the csv file - * - * @param Worksheet $worksheet - */ - protected function prepareHeaders(Worksheet $worksheet) + + public function getType() { - $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); - // we want to keep the order of the first row. So we will iterate on the first row of the results - $first_row = count($this->result) > 0 ? $this->result[0] : array(); - $header_line = array(); - - if ($this->formatterData['numerotation'] === true) { - $header_line[] = $this->translator->trans('Number'); - } - - foreach ($first_row as $key => $value) { - $header_line[] = $this->translator->trans( - $this->getLabel($key, '_header')); - } - - if (count($header_line) > 0) { - $worksheet->fromArray($header_line, NULL, 'A1'); - } + return FormatterInterface::TYPE_LIST; } - + /** - * Give the label corresponding to the given key and value. - * + * Give the label corresponding to the given key and value. + * * @param string $key * @param string $value + * + * @throws LogicException if the label is not found + * * @return string - * @throws \LogicException if the label is not found */ protected function getLabel($key, $value) { - - if ($this->labelsCache === null) { + if (null === $this->labelsCache) { $this->prepareCacheLabels(); } - - if (!\array_key_exists($key, $this->labelsCache)){ - throw new \OutOfBoundsException(sprintf("The key \"%s\" " - . "is not present in the list of keys handled by " - . "this query. Check your `getKeys` and `getLabels` " - . "methods. Available keys are %s.", $key, - \implode(", ", \array_keys($this->labelsCache)))); + + if (!array_key_exists($key, $this->labelsCache)) { + throw new OutOfBoundsException(sprintf( + 'The key "%s" ' + . 'is not present in the list of keys handled by ' + . 'this query. Check your `getKeys` and `getLabels` ' + . 'methods. Available keys are %s.', + $key, + implode(', ', array_keys($this->labelsCache)) + )); } - + return $this->labelsCache[$key]($value); } - + /** * Prepare the label cache which will be used by getLabel. This function * should be called only once in the generation lifecycle. @@ -272,14 +255,39 @@ class SpreadsheetListFormatter implements FormatterInterface { $export = $this->exportManager->getExport($this->exportAlias); $keys = $export->getQueryKeys($this->exportData); - - foreach($keys as $key) { + + foreach ($keys as $key) { // get an array with all values for this key if possible - $values = \array_map(function ($v) use ($key) { return $v[$key]; }, $this->result); + $values = array_map(function ($v) use ($key) { + return $v[$key]; + }, $this->result); // store the label in the labelsCache property $this->labelsCache[$key] = $export->getLabels($key, $values, $this->exportData); } } - - + + /** + * add the headers to the csv file. + */ + protected function prepareHeaders(Worksheet $worksheet) + { + $keys = $this->exportManager->getExport($this->exportAlias)->getQueryKeys($this->exportData); + // we want to keep the order of the first row. So we will iterate on the first row of the results + $first_row = count($this->result) > 0 ? $this->result[0] : []; + $header_line = []; + + if (true === $this->formatterData['numerotation']) { + $header_line[] = $this->translator->trans('Number'); + } + + foreach ($first_row as $key => $value) { + $header_line[] = $this->translator->trans( + $this->getLabel($key, '_header') + ); + } + + if (count($header_line) > 0) { + $worksheet->fromArray($header_line, null, 'A1'); + } + } } diff --git a/src/Bundle/ChillMainBundle/Export/FormatterInterface.php b/src/Bundle/ChillMainBundle/Export/FormatterInterface.php index c507a594f..f18822008 100644 --- a/src/Bundle/ChillMainBundle/Export/FormatterInterface.php +++ b/src/Bundle/ChillMainBundle/Export/FormatterInterface.php @@ -1,71 +1,58 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; use Symfony\Component\Form\FormBuilderInterface; -/** - * - * @author Julien Fastré - */ interface FormatterInterface { - const TYPE_TABULAR = 'tabular'; - const TYPE_LIST = 'list'; - - public function getType(); - - public function getName(); - + public const TYPE_LIST = 'list'; + + public const TYPE_TABULAR = 'tabular'; + /** * build a form, which will be used to collect data required for the execution * of this formatter. - * + * * @uses appendAggregatorForm - * @param FormBuilderInterface $builder - * @param String $exportAlias Alias of the export which is being executed. An export gets the data and implements the \Chill\MainBundle\Export\ExportInterface + * + * @param string $exportAlias Alias of the export which is being executed. An export gets the data and implements the \Chill\MainBundle\Export\ExportInterface * @param Array(String) $aggregatorAliases Array of the aliases of the aggregators. An aggregator do the "group by" on the data. $aggregatorAliases */ public function buildForm( - FormBuilderInterface $builder, - $exportAlias, - array $aggregatorAliases - ); - + FormBuilderInterface $builder, + $exportAlias, + array $aggregatorAliases + ); + + public function getName(); + /** - * Generate a response from the data collected on differents ExportElementInterface - * + * Generate a response from the data collected on differents ExportElementInterface. + * * @param mixed[] $result The result, as given by the ExportInterface * @param mixed[] $formatterData collected from the current form * @param string $exportAlias the id of the current export * @param array $filtersData an array containing the filters data. The key are the filters id, and the value are the data * @param array $aggregatorsData an array containing the aggregators data. The key are the filters id, and the value are the data + * * @return \Symfony\Component\HttpFoundation\Response The response to be shown */ public function getResponse( - $result, - $formatterData, - $exportAlias, - array $exportData, - array $filtersData, - array $aggregatorsData - ); - + $result, + $formatterData, + $exportAlias, + array $exportData, + array $filtersData, + array $aggregatorsData + ); + + public function getType(); } diff --git a/src/Bundle/ChillMainBundle/Export/GroupedExportInterface.php b/src/Bundle/ChillMainBundle/Export/GroupedExportInterface.php index 9330fd32b..f0ee4ea62 100644 --- a/src/Bundle/ChillMainBundle/Export/GroupedExportInterface.php +++ b/src/Bundle/ChillMainBundle/Export/GroupedExportInterface.php @@ -1,14 +1,19 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Export; @@ -23,36 +13,34 @@ use Doctrine\ORM\QueryBuilder; /** * Modifiers modify the export's query. - * - * Known subclasses : AggregatorInterface and FilterInterface * - * @author Julien Fastré + * Known subclasses : AggregatorInterface and FilterInterface */ interface ModifierInterface extends ExportElementInterface { /** - * The role required for executing this Modifier - * + * The role required for executing this Modifier. + * * If null, will used the ExportInterface::requiredRole role from * the current executing export. - * - * @return NULL|\Symfony\Component\Security\Core\Role\Role A role required to execute this ModifiersInterface + * + * @return \Symfony\Component\Security\Core\Role\Role|null A role required to execute this ModifiersInterface */ public function addRole(); - + /** - * On which type of Export this ModifiersInterface may apply. - * - * @return string the type on which the Modifiers apply - */ - public function applyOn(); - - /** - * Alter the query initiated by the export, to add the required statements - * (`GROUP BY`, `SELECT`, `WHERE`) - * + * Alter the query initiated by the export, to add the required statements + * (`GROUP BY`, `SELECT`, `WHERE`). + * * @param QueryBuilder $qb the QueryBuilder initiated by the Export (and eventually modified by other Modifiers) * @param mixed[] $data the data from the Form (builded by buildForm) */ public function alterQuery(QueryBuilder $qb, $data); + + /** + * On which type of Export this ModifiersInterface may apply. + * + * @return string the type on which the Modifiers apply + */ + public function applyOn(); } diff --git a/src/Bundle/ChillMainBundle/Form/AdvancedSearchType.php b/src/Bundle/ChillMainBundle/Form/AdvancedSearchType.php index a70a34b31..17b033ec1 100644 --- a/src/Bundle/ChillMainBundle/Form/AdvancedSearchType.php +++ b/src/Bundle/ChillMainBundle/Form/AdvancedSearchType.php @@ -1,59 +1,42 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form; +use Chill\MainBundle\Search\SearchProvider; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Search\SearchProvider; -/** - * - * - * @author Julien Fastré - */ class AdvancedSearchType extends AbstractType { /** - * * @var SearchProvider */ protected $searchProvider; - + public function __construct(SearchProvider $searchProvider) { $this->searchProvider = $searchProvider; } - public function buildForm(FormBuilderInterface $builder, array $options) { $this->searchProvider ->getHasAdvancedFormByName($options['search_service']) - ->createSearchForm($builder) - ; + ->createSearchForm($builder); } - + public function configureOptions(OptionsResolver $resolver) { $resolver ->setRequired('search_service') - ->setAllowedTypes('search_service', [ 'string' ]) - ; + ->setAllowedTypes('search_service', ['string']); } } diff --git a/src/Bundle/ChillMainBundle/Form/CenterType.php b/src/Bundle/ChillMainBundle/Form/CenterType.php index 9ab037304..2f493078f 100644 --- a/src/Bundle/ChillMainBundle/Form/CenterType.php +++ b/src/Bundle/ChillMainBundle/Form/CenterType.php @@ -1,23 +1,25 @@ add('name', TextType::class) - ; + ->add('name', TextType::class); } /** @@ -25,17 +27,16 @@ class CenterType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\MainBundle\Entity\Center' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\MainBundle\Entity\Center', + ]); } /** * @return string */ - public function getBlockPrefix() + public function getBlockPrefix() { - return 'chill_mainbundle_center'; - } - + return 'chill_mainbundle_center'; + } } diff --git a/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php b/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php index dfc2caa1f..c5f79d4de 100644 --- a/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php +++ b/src/Bundle/ChillMainBundle/Form/ChoiceLoader/PostalCodeChoiceLoader.php @@ -1,82 +1,67 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\ChoiceLoader; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; -use Chill\MainBundle\Repository\PostalCodeRepository; use Chill\MainBundle\Entity\PostalCode; +use Chill\MainBundle\Repository\PostalCodeRepository; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; +use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; + +use function call_user_func; /** - * Class PostalCodeChoiceLoader - * - * @package Chill\MainBundle\Form\ChoiceLoader - * @author Julien Fastré + * Class PostalCodeChoiceLoader. */ class PostalCodeChoiceLoader implements ChoiceLoaderInterface { - /** - * @var PostalCodeRepository - */ - protected $postalCodeRepository; - /** * @var array */ protected $lazyLoadedPostalCodes = []; - + + /** + * @var PostalCodeRepository + */ + protected $postalCodeRepository; + /** * PostalCodeChoiceLoader constructor. - * - * @param PostalCodeRepository $postalCodeRepository */ public function __construct(PostalCodeRepository $postalCodeRepository) { $this->postalCodeRepository = $postalCodeRepository; } - + /** * @param null $value - * @return ChoiceListInterface */ public function loadChoiceList($value = null): ChoiceListInterface { - $list = new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( - $this->lazyLoadedPostalCodes, - function(PostalCode $pc = null) use ($value) { - return \call_user_func($value, $pc); - }); - - return $list; + return new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( + $this->lazyLoadedPostalCodes, + function (?PostalCode $pc = null) use ($value) { + return call_user_func($value, $pc); + } + ); } - + /** - * @param array $values * @param null $value + * * @return array */ public function loadChoicesForValues(array $values, $value = null) { $choices = []; - - foreach($values as $value) { + + foreach ($values as $value) { if (empty($value)) { $choices[] = null; } else { @@ -86,27 +71,28 @@ class PostalCodeChoiceLoader implements ChoiceLoaderInterface return $choices; } - + /** - * @param array $choices * @param null $value + * * @return array|string[] */ public function loadValuesForChoices(array $choices, $value = null) { $values = []; - + foreach ($choices as $choice) { - if (NULL === $choice) { + if (null === $choice) { $values[] = null; + continue; } - - $id = \call_user_func($value, $choice); + + $id = call_user_func($value, $choice); $values[] = $id; $this->lazyLoadedPostalCodes[$id] = $choice; } - + return $values; } } diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php index 36383f7e3..252d7d43f 100644 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/AddressDataMapper.php @@ -1,68 +1,70 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\DataMapper; -use Symfony\Component\Form\DataMapperInterface; use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\PostalCode; -use Symfony\Component\Form\FormInterface; +use Iterator; +use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\FormInterface; /** * Add a data mapper to Address. - * + * * If the address is incomplete, the data mapper returns null */ class AddressDataMapper implements DataMapperInterface { /** - * * @param Address $address - * @param \Iterator $forms + * @param Iterator $forms */ public function mapDataToForms($address, $forms) { - if (NULL === $address) { + if (null === $address) { return; } - + if (!$address instanceof Address) { throw new UnexpectedTypeException($address, Address::class); } - + foreach ($forms as $key => $form) { /** @var FormInterface $form */ switch ($key) { case 'streetAddress1': $form->setData($address->getStreetAddress1()); + break; + case 'streetAddress2': $form->setData($address->getStreetAddress2()); + break; + case 'postCode': $form->setData($address->getPostcode()); + break; + case 'validFrom': $form->setData($address->getValidFrom()); + break; + case 'isNoAddress': $form->setData($address->isNoAddress()); + break; + default: break; } @@ -70,8 +72,7 @@ class AddressDataMapper implements DataMapperInterface } /** - * - * @param \Iterator $forms + * @param Iterator $forms * @param Address $address */ public function mapFormsToData($forms, &$address) @@ -79,40 +80,53 @@ class AddressDataMapper implements DataMapperInterface if (!$address instanceof Address) { $address = new Address(); } - + $isNoAddress = false; + foreach ($forms as $key => $form) { - if ($key === 'isNoAddress') { + if ('isNoAddress' === $key) { $isNoAddress = $form->get('isNoAddress')->getData(); } } - + foreach ($forms as $key => $form) { /** @var FormInterface $form */ - switch($key) { + switch ($key) { case 'postCode': if (!$form->getData() instanceof PostalCode && !$isNoAddress) { $address = null; + return; } $address->setPostcode($form->getData()); + break; + case 'streetAddress1': if (empty($form->getData()) && !$isNoAddress) { $address = null; + return; } $address->setStreetAddress1($form->getData()); + break; + case 'streetAddress2': $address->setStreetAddress2($form->getData()); + break; + case 'validFrom': $address->setValidFrom($form->getData()); + break; + case 'isNoAddress': $address->setIsNoAddress($form->getData()); + break; + default: break; } diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/ScopePickerDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/ScopePickerDataMapper.php index 816f62827..7039fe9a6 100644 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/ScopePickerDataMapper.php +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/ScopePickerDataMapper.php @@ -1,10 +1,16 @@ scope = $scope; } @@ -24,6 +30,7 @@ class ScopePickerDataMapper implements DataMapperInterface if ($this->scope instanceof Scope) { $forms['scope']->setData($this->scope); + return; } diff --git a/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php b/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php index d9b4ab730..6b38a6c71 100644 --- a/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php +++ b/src/Bundle/ChillMainBundle/Form/PermissionsGroupType.php @@ -1,75 +1,64 @@ add('name', TextType::class) - ; - - $flags = $this->getFlags(); - - if (count($flags) > 0) { - $builder - ->add('flags', ChoiceType::class, [ - 'choices' => \array_combine($flags, $flags), - 'multiple' => true, - 'expanded' => true, - 'required' => false - ]); - } - } - - /** - * - * @return array - */ - protected function getFlags(): array - { - $flags = []; - - foreach ($this->flagProviders as $flagProvider) { - $flags = \array_merge($flags, $flagProvider->getPermissionsGroupFlags()); - } - - return $flags; - } - + public function addFlagProvider(PermissionsGroupFlagProvider $provider) { $this->flagProviders[] = $provider; } + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('name', TextType::class); + + $flags = $this->getFlags(); + + if (count($flags) > 0) { + $builder + ->add('flags', ChoiceType::class, [ + 'choices' => array_combine($flags, $flags), + 'multiple' => true, + 'expanded' => true, + 'required' => false, + ]); + } + } + /** * @param OptionsResolverInterface $resolver */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\MainBundle\Entity\PermissionsGroup' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\MainBundle\Entity\PermissionsGroup', + ]); } /** @@ -79,4 +68,15 @@ class PermissionsGroupType extends AbstractType { return 'chill_mainbundle_permissionsgroup'; } + + protected function getFlags(): array + { + $flags = []; + + foreach ($this->flagProviders as $flagProvider) { + $flags = array_merge($flags, $flagProvider->getPermissionsGroupFlags()); + } + + return $flags; + } } diff --git a/src/Bundle/ChillMainBundle/Form/ScopeType.php b/src/Bundle/ChillMainBundle/Form/ScopeType.php index 12eb9fec4..9733f918f 100644 --- a/src/Bundle/ChillMainBundle/Form/ScopeType.php +++ b/src/Bundle/ChillMainBundle/Form/ScopeType.php @@ -1,23 +1,25 @@ add('name', TranslatableStringFormType::class) - ; + ->add('name', TranslatableStringFormType::class); } /** @@ -25,9 +27,9 @@ class ScopeType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\MainBundle\Entity\Scope' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\MainBundle\Entity\Scope', + ]); } /** diff --git a/src/Bundle/ChillMainBundle/Form/Type/AddressType.php b/src/Bundle/ChillMainBundle/Form/Type/AddressType.php index 68cfdda09..28ddc125f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/AddressType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/AddressType.php @@ -1,36 +1,25 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Form\Type\PostalCodeType; use Chill\MainBundle\Form\DataMapper\AddressDataMapper; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * A type to create/update Address entity + * A type to create/update Address entity. * * Options: * @@ -45,27 +34,29 @@ class AddressType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('street', TextType::class, array( - 'required' => !$options['has_no_address'] // true if has no address is false - )) - ->add('streetNumber', TextType::class, array( - 'required' => false - )) - ->add('postCode', PostalCodeType::class, array( - 'label' => 'Postal code', - 'placeholder' => 'Choose a postal code', - 'required' => !$options['has_no_address'] // true if has no address is false - )) - ; + ->add('street', TextType::class, [ + 'required' => !$options['has_no_address'], // true if has no address is false + ]) + ->add('streetNumber', TextType::class, [ + 'required' => false, + ]) + ->add('postCode', PostalCodeType::class, [ + 'label' => 'Postal code', + 'placeholder' => 'Choose a postal code', + 'required' => !$options['has_no_address'], // true if has no address is false + ]); if ($options['has_valid_from']) { $builder - ->add('validFrom', DateType::class, array( - 'required' => true, - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy' - ) - ); + ->add( + 'validFrom', + DateType::class, + [ + 'required' => true, + 'widget' => 'single_text', + 'format' => 'dd-MM-yyyy', + ] + ); } if ($options['has_no_address']) { @@ -74,13 +65,13 @@ class AddressType extends AbstractType 'required' => true, 'choices' => [ 'address.consider homeless' => true, - 'address.real address' => false + 'address.real address' => false, ], - 'label' => 'address.address_homeless' + 'label' => 'address.address_homeless', ]); } - if ($options['null_if_empty'] === TRUE) { + if (true === $options['null_if_empty']) { $builder->setDataMapper(new AddressDataMapper()); } } @@ -97,7 +88,6 @@ class AddressType extends AbstractType ->setAllowedTypes('has_no_address', 'bool') ->setDefined('null_if_empty') ->setDefault('null_if_empty', false) - ->setAllowedTypes('null_if_empty', 'bool') - ; + ->setAllowedTypes('null_if_empty', 'bool'); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/AppendScopeChoiceTypeTrait.php b/src/Bundle/ChillMainBundle/Form/Type/AppendScopeChoiceTypeTrait.php index 8de9134f1..86ffb8e26 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/AppendScopeChoiceTypeTrait.php +++ b/src/Bundle/ChillMainBundle/Form/Type/AppendScopeChoiceTypeTrait.php @@ -1,37 +1,26 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Form\Type\DataTransformer\ScopeTransformer; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\Persistence\ObjectManager; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Form\FormEvent; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Center; -use Symfony\Component\Security\Core\Role\Role; -use Chill\MainBundle\Form\Type\DataTransformer\ScopeTransformer; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Role\Role; /** * Trait to add an input with reachable scope for a given center and role. @@ -78,75 +67,72 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType; * * } * ``` - * - * @author Julien Fastré - * @author Champs Libres */ trait AppendScopeChoiceTypeTrait { - /** - * Append a scope choice field, with the scopes reachable by given - * user for the given role and center. - * - * The field is added on event FormEvents::PRE_SET_DATA - * - * @param FormBuilderInterface $builder - * @param Role $role - * @param Center $center - * @param User $user - * @param AuthorizationHelper $authorizationHelper - * @param TranslatableStringHelper $translatableStringHelper - * @param string $name - */ - protected function appendScopeChoices(FormBuilderInterface $builder, - Role $role, Center $center, User $user, - AuthorizationHelper $authorizationHelper, - TranslatableStringHelper $translatableStringHelper, - ObjectManager $om, $name = 'scope') - { - $reachableScopes = $authorizationHelper - ->getReachableScopes($user, $role, $center); - - $choices = array(); - foreach($reachableScopes as $scope) { - $choices[$scope->getId()] = $translatableStringHelper - ->localize($scope->getName()); - } - - $dataTransformer = new ScopeTransformer($om); - - $builder->addEventListener(FormEvents::PRE_SET_DATA, - function (FormEvent $event) use ($choices, $name, $dataTransformer, $builder) { - $form = $event->getForm(); - $form->add( - $builder - ->create($name, ChoiceType::class, array( - 'choices' => array_combine(array_values($choices),array_keys($choices)), - 'auto_initialize' => false - ) - ) - ->addModelTransformer($dataTransformer) - ->getForm() - ); - }); - } - /** * Append a `role` and `center` option to the form. * * The allowed types are : * - Chill\MainBundle\Entity\Center for center * - Symfony\Component\Security\Core\Role\Role for role - * - * @param OptionsResolver $resolver */ public function appendScopeChoicesOptions(OptionsResolver $resolver) { $resolver - ->setRequired(array('center', 'role')) - ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center') - ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role') - ; + ->setRequired(['center', 'role']) + ->setAllowedTypes('center', 'Chill\MainBundle\Entity\Center') + ->setAllowedTypes('role', 'Symfony\Component\Security\Core\Role\Role'); } + /** + * Append a scope choice field, with the scopes reachable by given + * user for the given role and center. + * + * The field is added on event FormEvents::PRE_SET_DATA + * + * @param string $name + */ + protected function appendScopeChoices( + FormBuilderInterface $builder, + Role $role, + Center $center, + User $user, + AuthorizationHelper $authorizationHelper, + TranslatableStringHelper $translatableStringHelper, + ObjectManager $om, + $name = 'scope' + ) { + $reachableScopes = $authorizationHelper + ->getReachableScopes($user, $role, $center); + + $choices = []; + + foreach ($reachableScopes as $scope) { + $choices[$scope->getId()] = $translatableStringHelper + ->localize($scope->getName()); + } + + $dataTransformer = new ScopeTransformer($om); + + $builder->addEventListener( + FormEvents::PRE_SET_DATA, + function (FormEvent $event) use ($choices, $name, $dataTransformer, $builder) { + $form = $event->getForm(); + $form->add( + $builder + ->create( + $name, + ChoiceType::class, + [ + 'choices' => array_combine(array_values($choices), array_keys($choices)), + 'auto_initialize' => false, + ] + ) + ->addModelTransformer($dataTransformer) + ->getForm() + ); + } + ); + } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/CenterType.php b/src/Bundle/ChillMainBundle/Form/Type/CenterType.php index ba039c938..fbb967a75 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/CenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/CenterType.php @@ -1,40 +1,39 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use RuntimeException; use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -/** - * - * - * @author Julien Fastré - */ class CenterType extends AbstractType { + /** + * associative array where keys are center.id and + * value are center objects. + * + * @var Center[] + */ + protected $reachableCenters = []; + + /** + * @var CenterTransformer + */ + protected $transformer; + /** * The user linked with this type. * @@ -42,55 +41,28 @@ class CenterType extends AbstractType */ protected $user; - /** - * associative array where keys are center.id and - * value are center objects - * - * @var Center[] - */ - protected $reachableCenters = array(); - - /** - * - * @var CenterTransformer - */ - protected $transformer; - - public function __construct(TokenStorageInterface $tokenStorage, - CenterTransformer $transformer) - { + public function __construct( + TokenStorageInterface $tokenStorage, + CenterTransformer $transformer + ) { $this->user = $tokenStorage->getToken()->getUser(); $this->transformer = $transformer; $this->prepareReachableCenterByUser(); } /** - * return a 'hidden' field if only one center is available. - * - * Return a 'choice' field if more than one center is available. - * - * @return string - * @throws \RuntimeException if the user is not associated with any center + * add a data transformer if user can reach only one center. */ - public function getParent() + public function buildForm(FormBuilderInterface $builder, array $options) { - $nbReachableCenters = count($this->reachableCenters); - - if ($nbReachableCenters === 0) { - throw new \RuntimeException("The user is not associated with " - . "any center. Associate user with a center"); - } elseif ($nbReachableCenters === 1) { - return HiddenType::class; - } else { - return EntityType::class; + if ($this->getParent() === HiddenType::class) { + $builder->addModelTransformer($this->transformer); } } /** * configure default options, i.e. add choices if user can reach multiple * centers. - * - * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { @@ -101,36 +73,49 @@ class CenterType extends AbstractType } /** - * add a data transformer if user can reach only one center + * return a 'hidden' field if only one center is available. * - * @param FormBuilderInterface $builder - * @param array $options + * Return a 'choice' field if more than one center is available. + * + * @throws RuntimeException if the user is not associated with any center + * + * @return string */ - public function buildForm(FormBuilderInterface $builder, array $options) + public function getParent() { - if ($this->getParent() === HiddenType::class) { - $builder->addModelTransformer($this->transformer); + $nbReachableCenters = count($this->reachableCenters); + + if (0 === $nbReachableCenters) { + throw new RuntimeException('The user is not associated with ' + . 'any center. Associate user with a center'); } + + if (1 === $nbReachableCenters) { + return HiddenType::class; + } + + return EntityType::class; } /** * populate reachableCenters as an associative array where * keys are center.id and value are center entities. - * */ private function prepareReachableCenterByUser() { $groupCenters = $this->user->getGroupCenters(); foreach ($groupCenters as $groupCenter) { - $center = $groupCenter->getCenter(); - if (!array_key_exists($center->getId(), - $this->reachableCenters)) { + if ( + !array_key_exists( + $center->getId(), + $this->reachableCenters + ) + ) { $this->reachableCenters[$center->getId()] = $center; } } } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php index 1068522c9..b226662a8 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillCollectionType.php @@ -1,50 +1,29 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormInterface; /** - * Available options : - * + * Available options :. + * * - `button_add_label` * - `button_remove_label` * - `identifier`: an identifier to identify the kind of collecton. Useful if some * javascript should be launched associated to `add_entry`, `remove_entry` events. - * - * - * @author Julien Fastré */ class ChillCollectionType extends AbstractType { - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setDefaults([ - 'button_add_label' => 'Add an entry', - 'button_remove_label' => 'Remove entry', - 'identifier' => '' - ]); - } - public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['button_add_label'] = $options['button_add_label']; @@ -53,7 +32,17 @@ class ChillCollectionType extends AbstractType $view->vars['allow_add'] = (int) $options['allow_add']; $view->vars['identifier'] = $options['identifier']; } - + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefaults([ + 'button_add_label' => 'Add an entry', + 'button_remove_label' => 'Remove entry', + 'identifier' => '', + ]); + } + public function getParent() { return \Symfony\Component\Form\Extension\Core\Type\CollectionType::class; diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillDateTimeType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillDateTimeType.php index 07adc0cb8..d1699b9d3 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillDateTimeType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillDateTimeType.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; use Symfony\Component\Form\AbstractType; @@ -23,11 +15,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** * Display the date in a date picker. - * + * * Extends the symfony `Symfony\Component\Form\Extension\Core\Type\DateType` * to automatically create a date picker. - * - * @author Mathieu Jaumotte */ class ChillDateTimeType extends AbstractType { @@ -39,10 +29,9 @@ class ChillDateTimeType extends AbstractType ->setDefault('time_widget', 'choice') ->setDefault('minutes', range(0, 59, 5)) ->setDefault('hours', range(8, 22)) - ->setDefault('html5', true) - ; + ->setDefault('html5', true); } - + public function getParent() { return DateTimeType::class; diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php index 2f5a6945c..b8d00dc5c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillDateType.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; use Symfony\Component\Form\AbstractType; @@ -23,11 +15,9 @@ use Symfony\Component\OptionsResolver\OptionsResolver; /** * Display the date in a date picker. - * + * * Extends the symfony `Symfony\Component\Form\Extension\Core\Type\DateType` * to automatically create a date picker. - * - * @author Julien Fastré */ class ChillDateType extends AbstractType { @@ -35,11 +25,10 @@ class ChillDateType extends AbstractType { $resolver ->setDefault('widget', 'single_text') - ->setDefault('attr', [ 'class' => 'datepicker' ]) - ->setDefault('format', 'dd-MM-yyyy') - ; + ->setDefault('attr', ['class' => 'datepicker']) + ->setDefault('format', 'dd-MM-yyyy'); } - + public function getParent() { return DateType::class; diff --git a/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php b/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php index 37c436f7c..9cca05aa5 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ChillTextareaType.php @@ -1,45 +1,38 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Create a Textarea - * - * By default, add a WYSIWYG editor. - * - * Options: - * - * * `disable_editor`: set true to disable editor + * Create a Textarea. * + * By default, add a WYSIWYG editor. + * + * Options: + * + * * `disable_editor`: set true to disable editor */ final class ChillTextareaType extends AbstractType { - public function getParent() + public function buildView(FormView $view, FormInterface $form, array $options) { - return TextareaType::class; + if (!$options['disable_editor']) { + $view->vars['attr']['ckeditor'] = true; + } } - + public function configureOptions(OptionsResolver $resolver) { $resolver @@ -47,11 +40,9 @@ final class ChillTextareaType extends AbstractType ->setDefault('disable_editor', false) ->setAllowedTypes('disable_editor', 'bool'); } - - public function buildView(FormView $view, FormInterface $form, array $options) + + public function getParent() { - if (!$options['disable_editor']) { - $view->vars['attr']['ckeditor'] = true; - } + return TextareaType::class; } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php index a6e664769..638a34f1f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/CommentType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/CommentType.php @@ -1,26 +1,17 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; +use DateTime; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; -use Chill\MainBundle\Form\Type\ChillTextareaType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; @@ -45,16 +36,15 @@ class CommentType extends AbstractType { $builder ->add('comment', ChillTextareaType::class, [ - 'disable_editor' => $options['disable_editor'] - ]) - ; + 'disable_editor' => $options['disable_editor'], + ]); $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) { $data = $event->getForm()->getData(); $comment = $event->getData(); if ($data->getComment() !== $comment['comment']) { - $data->setDate(new \DateTime()); + $data->setDate(new DateTime()); $data->setUserId($this->user->getId()); $event->getForm()->setData($data); } @@ -64,7 +54,8 @@ class CommentType extends AbstractType public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace( - $view->vars, [ + $view->vars, + [ 'hideLabel' => true, ] ); @@ -77,7 +68,7 @@ class CommentType extends AbstractType ->setAllowedTypes('disable_editor', 'bool') ->setDefaults([ 'data_class' => CommentEmbeddable::class, - 'disable_editor' => false + 'disable_editor' => false, ]); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php index 0fe628401..d3b307988 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ComposedGroupCenterType.php @@ -1,54 +1,36 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\OptionsResolver\OptionsResolver; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\PermissionsGroup; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Entity\PermissionsGroup; -use Chill\MainBundle\Entity\Center; - -/** - * - * - * @author Julien Fastré - */ class ComposedGroupCenterType extends AbstractType { - public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('permissionsgroup', EntityType::class, array( + $builder->add('permissionsgroup', EntityType::class, [ 'class' => 'Chill\MainBundle\Entity\PermissionsGroup', - 'choice_label' => function(PermissionsGroup $group) { + 'choice_label' => function (PermissionsGroup $group) { return $group->getName(); - } - ))->add('center', EntityType::class, array( + }, + ])->add('center', EntityType::class, [ 'class' => 'Chill\MainBundle\Entity\Center', - 'choice_label' => function(Center $center) { + 'choice_label' => function (Center $center) { return $center->getName(); - } - )) - ; + }, + ]); } public function configureOptions(OptionsResolver $resolver) @@ -60,5 +42,4 @@ class ComposedGroupCenterType extends AbstractType { return 'composed_groupcenter'; } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php b/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php index c06394845..98b9a6ea7 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ComposedRoleScopeType.php @@ -1,71 +1,49 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - -use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Security\RoleProvider; - +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; /** * Form to Edit/create a role scope. If the role scope does not * exists in the database, he is generated. - * - * @author Julien Fastré - * @author Champs Libres */ class ComposedRoleScopeType extends AbstractType { /** - * - * @var string[] - */ - private $roles = array(); - - /** - * - * @var string[] - */ - private $rolesWithoutScope = array(); - - /** - * - * @var TranslatableStringHelper - */ - private $translatableStringHelper; - - /** - * * @var RoleProvider */ private $roleProvider; + /** + * @var string[] + */ + private $roles = []; + + /** + * @var string[] + */ + private $rolesWithoutScope = []; + + /** + * @var TranslatableStringHelper + */ + private $translatableStringHelper; + public function __construct( TranslatableStringHelper $translatableStringHelper, RoleProvider $roleProvider @@ -83,40 +61,39 @@ class ComposedRoleScopeType extends AbstractType $rolesWithoutScopes = $this->rolesWithoutScope; //build roles - $values = array(); + $values = []; + foreach ($this->roles as $role) { $values[$role] = $role; } $builder - ->add('role', ChoiceType::class, array( - 'choices' => array_combine(array_values($values),array_keys($values)), - 'placeholder' => 'Choose amongst roles', - 'choice_attr' => function($role) use ($rolesWithoutScopes) { + ->add('role', ChoiceType::class, [ + 'choices' => array_combine(array_values($values), array_keys($values)), + 'placeholder' => 'Choose amongst roles', + 'choice_attr' => function ($role) use ($rolesWithoutScopes) { if (in_array($role, $rolesWithoutScopes)) { - return array('data-has-scope' => '0'); - } else { - return array('data-has-scope' => '1'); + return ['data-has-scope' => '0']; } - }, - 'group_by' => function($role, $key, $index) { + + return ['data-has-scope' => '1']; + }, + 'group_by' => function ($role, $key, $index) { return $this->roleProvider->getRoleTitle($role); - } - )) - ->add('scope', EntityType::class, array( + }, + ]) + ->add('scope', EntityType::class, [ 'class' => 'ChillMainBundle:Scope', - 'choice_label' => function(Scope $scope) use ($translatableStringHelper) { + 'choice_label' => function (Scope $scope) use ($translatableStringHelper) { return $translatableStringHelper->localize($scope->getName()); }, 'required' => false, - 'data' => null - )); - + 'data' => null, + ]); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('data_class', 'Chill\MainBundle\Entity\RoleScope'); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php index 4b1b9a2d9..f474999ba 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/CenterTransformer.php @@ -1,70 +1,58 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\DataTransformer; -use Symfony\Component\Form\DataTransformerInterface; use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; /** - * Transform a center object to his id, and vice-versa - * - * @author Julien Fastré + * Transform a center object to his id, and vice-versa. */ class CenterTransformer implements DataTransformerInterface { /** - * * @var ObjectManager */ private $om; - - public function __construct(ObjectManager $om) + + public function __construct(ObjectManager $om) { $this->om = $om; } public function reverseTransform($id) { - if ($id === NULL) { - return NULL; + if (null === $id) { + return null; } - + $center = $this->om->getRepository('ChillMainBundle:Center') - ->find($id); - - if ($center === NULL) { + ->find($id); + + if (null === $center) { throw new TransformationFailedException(sprintf( - 'No center found with id %d', $id)); + 'No center found with id %d', + $id + )); } - + return $center; } public function transform($center) { - if ($center === NULL) { + if (null === $center) { return ''; } - + return $center->getId(); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php index 29a81447c..caf70beb7 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/DateIntervalTransformer.php @@ -1,36 +1,41 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type\DataTransformer; +use DateInterval; +use Exception; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; -/** - * - * - * @author Julien Fastré - */ class DateIntervalTransformer implements DataTransformerInterface { + public function reverseTransform($value) + { + if (empty($value) or empty($value['n'])) { + return null; + } + + $string = 'P' . $value['n'] . $value['unit']; + + try { + return new DateInterval($string); + } catch (Exception $e) { + throw new TransformationFailedException('Could not transform value ' + . 'into DateInterval', 1542, $e); + } + } + /** - * - * @param \DateInterval $value + * @param DateInterval $value + * * @throws UnexpectedTypeException */ public function transform($value) @@ -38,55 +43,41 @@ class DateIntervalTransformer implements DataTransformerInterface if (empty($value)) { return null; } - - if (!$value instanceof \DateInterval) { - throw new UnexpectedTypeException($value, \DateInterval::class); + + if (!$value instanceof DateInterval) { + throw new UnexpectedTypeException($value, DateInterval::class); } - - if ($value->d > 0) { + + if (0 < $value->d) { // we check for weeks (weeks are converted to 7 days) if ($value->d % 7 === 0) { return [ 'n' => $value->d / 7, - 'unit' => 'W' - ]; - } else { - return [ - 'n' => $value->d, - 'unit' => 'D' + 'unit' => 'W', ]; } - } elseif ($value->m > 0) { + return [ - 'n' => $value->m, - 'unit' => 'M' - ]; - } elseif ($value->y > 0) { - return [ - 'n' => $value->y, - 'unit' => 'Y' + 'n' => $value->d, + 'unit' => 'D', ]; } - + + if (0 < $value->m) { + return [ + 'n' => $value->m, + 'unit' => 'M', + ]; + } + + if (0 < $value->y) { + return [ + 'n' => $value->y, + 'unit' => 'Y', + ]; + } + throw new TransformationFailedException('the date interval does not ' . 'contains any days, months or years'); } - - public function reverseTransform($value) - { - if (empty($value) or empty($value['n'])) { - return null; - } - - $string = 'P'.$value['n'].$value['unit']; - - try { - return new \DateInterval($string); - } catch (\Exception $e) { - throw new TransformationFailedException("Could not transform value " - . "into DateInterval", 1542, $e); - } - - - } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php index 4686a5e17..7fa818368 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/MultipleObjectsToIdTransformer.php @@ -1,74 +1,46 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\DataTransformer; -use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Form\Exception\TransformationFailedException; -use Doctrine\Persistence\ObjectManager; use Doctrine\Common\Collections\ArrayCollection; - +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\DataTransformerInterface; + class MultipleObjectsToIdTransformer implements DataTransformerInterface { /** - * @var ObjectManager - */ - private $em; - - /** - * @var string - */ + * @var string + */ private $class; - + /** - * @param ObjectManager $em - */ + * @var ObjectManager + */ + private $em; + + /** + * @param mixed $class + */ public function __construct(ObjectManager $em, $class) { $this->em = $em; $this->class = $class; } - - /** - * Transforms an object (use) to a string (id). - * - * @param array $array - * @return ArrayCollection - */ - public function transform($array) - { - $ret = array(); - foreach ($array as $el) { - $ret[] = ($el->getId()); - } - - return $ret; - } - /** - * Transforms a string (id) to an object (item). - * - * @param string $id - * @return ArrayCollection - */ + * Transforms a string (id) to an object (item). + * + * @param mixed $array + * + * @return ArrayCollection + */ public function reverseTransform($array) { $ret = new ArrayCollection(); @@ -80,6 +52,25 @@ class MultipleObjectsToIdTransformer implements DataTransformerInterface ->find($el) ); } + return $ret; } -} \ No newline at end of file + + /** + * Transforms an object (use) to a string (id). + * + * @param array $array + * + * @return ArrayCollection + */ + public function transform($array) + { + $ret = []; + + foreach ($array as $el) { + $ret[] = ($el->getId()); + } + + return $ret; + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php index d041dce7c..0dfb3a12e 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ObjectToIdTransformer.php @@ -1,43 +1,32 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\DataTransformer; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; -use Doctrine\Persistence\ObjectManager; class ObjectToIdTransformer implements DataTransformerInterface { - /** - * @var ObjectManager - */ - private $om; - /** * @var string */ private $class; /** - * @param ObjectManager $om + * @var ObjectManager + */ + private $om; + + /** + * @param mixed $class */ public function __construct(ObjectManager $om, $class) { @@ -46,26 +35,13 @@ class ObjectToIdTransformer implements DataTransformerInterface } /** - * Transforms an object to a string (id) - * - * @param Object|null $Object - * @return string - */ - public function transform($object) - { - if (!$object) { - return ""; - } - - return $object->getId(); - } - - /** - * Transforms a string (id) to an object + * Transforms a string (id) to an object. * * @param string $id - * @return Object|null + * * @throws TransformationFailedException if object is not found. + * + * @return object|null */ public function reverseTransform($id) { @@ -75,13 +51,28 @@ class ObjectToIdTransformer implements DataTransformerInterface $object = $this->om ->getRepository($this->class) - ->find($id) - ; + ->find($id); - if (! $object) { + if (!$object) { throw new TransformationFailedException(); } return $object; } -} \ No newline at end of file + + /** + * Transforms an object to a string (id). + * + * @param mixed $object + * + * @return string + */ + public function transform($object) + { + if (!$object) { + return ''; + } + + return $object->getId(); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php index 09ef90063..0cf9fc459 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DataTransformer/ScopeTransformer.php @@ -1,77 +1,59 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\DataTransformer; -use Symfony\Component\Form\DataTransformerInterface; -use Doctrine\Persistence\ObjectManager; -use Symfony\Component\Form\Exception\TransformationFailedException; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; -/** - * - * - * @author Julien Fastré - */ class ScopeTransformer implements DataTransformerInterface { /** - * - * @var ObjectManager - */ - protected $om; - - /** - * * @var TranslatableStringHelper */ protected $helper; - + + /** + * @var ObjectManager + */ + protected $om; + public function __construct(ObjectManager $om) { $this->om = $om; } - - public function transform($scope) - { - if ($scope === NULL) { - return NULL; - } - - return $scope->getId(); - } public function reverseTransform($id) { - if ($id == NULL) { - return NULL; + if (null == $id) { + return null; } - + $scope = $this->om->getRepository('ChillMainBundle:Scope') - ->find($id); - - if ($scope === NULL) { - throw new TransformationFailedException(sprintf("The scope with id " + ->find($id); + + if (null === $scope) { + throw new TransformationFailedException(sprintf('The scope with id ' . "'%d' were not found", $id)); } - + return $scope; } + public function transform($scope) + { + if (null === $scope) { + return null; + } + + return $scope->getId(); + } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php b/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php index 5879bc525..8d44992d7 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/DateIntervalType.php @@ -1,40 +1,35 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Form\Type; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\Extension\Core\Type\IntegerType; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Chill\MainBundle\Form\Type\DataTransformer\DateIntervalTransformer; -use Symfony\Component\Validator\Constraints\GreaterThan; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; - /** - * Show a dateInterval type - * + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Form\Type; + +use Chill\MainBundle\Form\Type\DataTransformer\DateIntervalTransformer; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\GreaterThan; + +use function array_diff; +use function array_values; +use function implode; + +/** + * Show a dateInterval type. + * * Options: - * - * - `unit_choices`: an array of available units choices. - * - * The oiriginal `unit_choices` are : + * + * - `unit_choices`: an array of available units choices. + * + * The oiriginal `unit_choices` are : * ``` * [ * 'Days' => 'D', @@ -43,11 +38,11 @@ use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; * 'Years' => 'Y' * ] * ``` - * + * * You can remove one or more entries: - * + * * ``` - * $builder + * $builder * ->add('duration', DateIntervalType::class, array( * 'unit_choices' => [ * 'Years' => 'Y', @@ -55,7 +50,6 @@ use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; * ] * )); * ``` - * */ class DateIntervalType extends AbstractType { @@ -66,18 +60,17 @@ class DateIntervalType extends AbstractType 'scale' => 0, 'constraints' => [ new GreaterThan([ - 'value' => 0 - ]) - ] + 'value' => 0, + ]), + ], ]) ->add('unit', ChoiceType::class, [ 'choices' => $options['unit_choices'], - ]) - ; - + ]); + $builder->addModelTransformer(new DateIntervalTransformer()); } - + public function configureOptions(OptionsResolver $resolver) { $resolver @@ -86,23 +79,24 @@ class DateIntervalType extends AbstractType 'Days' => 'D', 'Weeks' => 'W', 'Months' => 'M', - 'Years' => 'Y' + 'Years' => 'Y', ]) - ->setAllowedValues('unit_choices', function($values) { - if (FALSE === is_array($values)) { - throw new InvalidOptionsException("The value `unit_choice` should be an array"); + ->setAllowedValues('unit_choices', function ($values) { + if (false === is_array($values)) { + throw new InvalidOptionsException('The value `unit_choice` should be an array'); } - - $diff = \array_diff(\array_values($values), ['D', 'W', 'M', 'Y']); + + $diff = array_diff(array_values($values), ['D', 'W', 'M', 'Y']); + if (count($diff) == 0) { return true; - } else { - throw new InvalidOptionsException(sprintf("The values of the " - . "units should be 'D', 'W', 'M', 'Y', those are invalid: %s", - \implode(', ', $diff))); } - }) - ; - } + throw new InvalidOptionsException(sprintf( + 'The values of the ' + . "units should be 'D', 'W', 'M', 'Y', those are invalid: %s", + implode(', ', $diff) + )); + }); + } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php index dd2125546..b0ff4d51c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/AggregatorType.php @@ -1,40 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\MainBundle\Export\ExportManager; - -/** - * - * - * @author Julien Fastré - */ class AggregatorType extends AbstractType { - public function __construct() { } @@ -45,30 +27,27 @@ class AggregatorType extends AbstractType $aggregator = $exportManager->getAggregator($options['aggregator_alias']); $builder - ->add('enabled', CheckboxType::class, array( - 'value' => true, - 'required' => false, - 'data' => false - )); + ->add('enabled', CheckboxType::class, [ + 'value' => true, + 'required' => false, + 'data' => false, + ]); - $filterFormBuilder = $builder->create('form', FormType::class, array( - 'compound' => true, - 'required' => false, - 'error_bubbling' => false - )); + $filterFormBuilder = $builder->create('form', FormType::class, [ + 'compound' => true, + 'required' => false, + 'error_bubbling' => false, + ]); $aggregator->buildForm($filterFormBuilder); $builder->add($filterFormBuilder); - } public function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('aggregator_alias') - ->setRequired('export_manager') - ->setDefault('compound', true) - ->setDefault('error_bubbling', false) - ; + ->setRequired('export_manager') + ->setDefault('compound', true) + ->setDefault('error_bubbling', false); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php index 24dd63dd3..b84e85892 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/ExportType.php @@ -1,57 +1,36 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; -use Chill\MainBundle\Form\Type\Export\FilterType; -use Chill\MainBundle\Form\Type\Export\AggregatorType; -use Symfony\Component\Form\Extension\Core\Type\FormType; use Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint; -use Chill\MainBundle\Export\ExportElementWithValidationInterface; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * - * - * @author Julien Fastré - */ class ExportType extends AbstractType { + public const AGGREGATOR_KEY = 'aggregators'; + + public const EXPORT_KEY = 'export'; + + public const FILTER_KEY = 'filters'; + + public const PICK_FORMATTER_KEY = 'pick_formatter'; + /** - * * @var ExportManager */ protected $exportManager; - const FILTER_KEY = 'filters'; - const AGGREGATOR_KEY = 'aggregators'; - const PICK_FORMATTER_KEY = 'pick_formatter'; - const EXPORT_KEY = 'export'; - public function __construct(ExportManager $exportManager) { $this->exportManager = $exportManager; @@ -61,12 +40,11 @@ class ExportType extends AbstractType { $export = $this->exportManager->getExport($options['export_alias']); - $exportOptions = array( + $exportOptions = [ 'compound' => true, - 'constraints' => array( - - ) - ); + 'constraints' => [ + ], + ]; // add a contraint if required by export $exportBuilder = $builder->create(self::EXPORT_KEY/*, FormType::class, $exportOptions*/); @@ -78,66 +56,65 @@ class ExportType extends AbstractType if ($export instanceof \Chill\MainBundle\Export\ExportInterface) { //add filters $filters = $this->exportManager->getFiltersApplyingOn($export, $options['picked_centers']); - $filterBuilder = $builder->create(self::FILTER_KEY, FormType::class, array('compound' => true)); + $filterBuilder = $builder->create(self::FILTER_KEY, FormType::class, ['compound' => true]); - foreach($filters as $alias => $filter) { - $filterBuilder->add($alias, FilterType::class, array( + foreach ($filters as $alias => $filter) { + $filterBuilder->add($alias, FilterType::class, [ 'filter_alias' => $alias, 'export_manager' => $this->exportManager, 'label' => $filter->getTitle(), - 'constraints' => array( - new ExportElementConstraint(['element' => $filter]) - ) - )); + 'constraints' => [ + new ExportElementConstraint(['element' => $filter]), + ], + ]); } $builder->add($filterBuilder); //add aggregators $aggregators = $this->exportManager - ->getAggregatorsApplyingOn($export, $options['picked_centers']); - $aggregatorBuilder = $builder->create(self::AGGREGATOR_KEY, FormType::class, - array('compound' => true)); + ->getAggregatorsApplyingOn($export, $options['picked_centers']); + $aggregatorBuilder = $builder->create( + self::AGGREGATOR_KEY, + FormType::class, + ['compound' => true] + ); - foreach($aggregators as $alias => $aggregator) { - $aggregatorBuilder->add($alias, AggregatorType::class, array( + foreach ($aggregators as $alias => $aggregator) { + $aggregatorBuilder->add($alias, AggregatorType::class, [ 'aggregator_alias' => $alias, 'export_manager' => $this->exportManager, 'label' => $aggregator->getTitle(), - 'constraints' => array( - new ExportElementConstraint(['element' => $aggregator]) - ) - )); + 'constraints' => [ + new ExportElementConstraint(['element' => $aggregator]), + ], + ]); } $builder->add($aggregatorBuilder); } // add export form - $exportBuilder = $builder->create(self::EXPORT_KEY, FormType::class, array('compound' => true)); + $exportBuilder = $builder->create(self::EXPORT_KEY, FormType::class, ['compound' => true]); $this->exportManager->getExport($options['export_alias']) - ->buildForm($exportBuilder); + ->buildForm($exportBuilder); $builder->add($exportBuilder); if ($export instanceof \Chill\MainBundle\Export\ExportInterface) { - $builder->add(self::PICK_FORMATTER_KEY, PickFormatterType::class, array( - 'export_alias' => $options['export_alias'] - )); + $builder->add(self::PICK_FORMATTER_KEY, PickFormatterType::class, [ + 'export_alias' => $options['export_alias'], + ]); } - } - public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired(array('export_alias', 'picked_centers')) - ->setAllowedTypes('export_alias', array('string')) - ->setDefault('compound', true) - ->setDefault('constraints', array( - //new \Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint() - )) - ; - + $resolver->setRequired(['export_alias', 'picked_centers']) + ->setAllowedTypes('export_alias', ['string']) + ->setDefault('compound', true) + ->setDefault('constraints', [ + //new \Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint() + ]); } public function getParent() diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php index 21f1bcd48..1dbfccf59 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/FilterType.php @@ -1,42 +1,23 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; -use Chill\MainBundle\Export\ExportManager; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; -use Chill\MainBundle\Export\ExportElementWithValidationInterface; -use Symfony\Component\Validator\Constraints as Assert; -use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * - * - * @author Julien Fastré - */ class FilterType extends AbstractType { - const ENABLED_FIELD = 'enabled'; + public const ENABLED_FIELD = 'enabled'; public function __construct() { @@ -44,35 +25,31 @@ class FilterType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { - $exportManager = $options['export_manager']; $filter = $exportManager->getFilter($options['filter_alias']); $builder - ->add(self::ENABLED_FIELD, CheckboxType::class, array( - 'value' => true, - 'data' => false, - 'required' => false - )); + ->add(self::ENABLED_FIELD, CheckboxType::class, [ + 'value' => true, + 'data' => false, + 'required' => false, + ]); - $filterFormBuilder = $builder->create('form', FormType::class, array( + $filterFormBuilder = $builder->create('form', FormType::class, [ 'compound' => true, 'error_bubbling' => false, 'required' => false, - )); + ]); $filter->buildForm($filterFormBuilder); $builder->add($filterFormBuilder); - } public function configureOptions(OptionsResolver $resolver) { $resolver->setRequired('filter_alias') - ->setRequired('export_manager') - ->setDefault('compound', true) - ->setDefault('error_bubbling', false) - ; + ->setRequired('export_manager') + ->setDefault('compound', true) + ->setDefault('error_bubbling', false); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/FormatterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/FormatterType.php index 023822d12..9c0a91fec 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/FormatterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/FormatterType.php @@ -1,59 +1,45 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Export\ExportManager; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; -/** - * - * - * @author Julien Fastré - */ class FormatterType extends AbstractType { /** - * * @var ExportManager */ protected $exportManager; - - public function __construct(ExportManager $manager) + + public function __construct(ExportManager $manager) { $this->exportManager = $manager; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired(array('formatter_alias', 'export_alias', - 'aggregator_aliases')); - } - + public function buildForm(FormBuilderInterface $builder, array $options) { $formatter = $this->exportManager->getFormatter($options['formatter_alias']); - - $formatter->buildForm($builder, $options['export_alias'], - $options['aggregator_aliases']); + + $formatter->buildForm( + $builder, + $options['export_alias'], + $options['aggregator_aliases'] + ); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setRequired(['formatter_alias', 'export_alias', + 'aggregator_aliases', ]); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php index 7f7143a4e..a3813533f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php @@ -1,182 +1,184 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; +use Chill\MainBundle\Center\GroupingCenterInterface; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\MainBundle\Export\ExportManager; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Entity\Center; -use Chill\MainBundle\Center\GroupingCenterInterface; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Form\CallbackTransformer; -use Doctrine\Common\Collections\Collection; + +use function array_intersect; +use function array_key_exists; +use function array_merge; +use function array_unique; +use function in_array; /** - * Pick centers amongst available centers for the user - * + * Pick centers amongst available centers for the user. */ class PickCenterType extends AbstractType { + public const CENTERS_IDENTIFIERS = 'c'; + /** - * - * @var \Symfony\Component\Security\Core\User\UserInterface - */ - protected $user; - - /** - * - * @var ExportManager - */ - protected $exportManager; - - /** - * - * @var GroupingCenterInterface[] - */ - protected $groupingCenters = []; - - const CENTERS_IDENTIFIERS = 'c'; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - - public function __construct(TokenStorageInterface $tokenStorage, - ExportManager $exportManager, AuthorizationHelper $authorizationHelper) - { + + /** + * @var ExportManager + */ + protected $exportManager; + + /** + * @var GroupingCenterInterface[] + */ + protected $groupingCenters = []; + + /** + * @var \Symfony\Component\Security\Core\User\UserInterface + */ + protected $user; + + public function __construct( + TokenStorageInterface $tokenStorage, + ExportManager $exportManager, + AuthorizationHelper $authorizationHelper + ) { $this->exportManager = $exportManager; $this->user = $tokenStorage->getToken()->getUser(); $this->authorizationHelper = $authorizationHelper; } - - - public function configureOptions(OptionsResolver $resolver) + + public function addGroupingCenter(GroupingCenterInterface $grouping) { - $resolver->setRequired('export_alias') - ; + $this->groupingCenters[md5($grouping->getName())] = $grouping; } - + public function buildForm(FormBuilderInterface $builder, array $options) { $export = $this->exportManager->getExport($options['export_alias']); - $centers = $this->authorizationHelper->getReachableCenters($this->user, - $export->requiredRole()); - - $builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, array( - 'class' => 'ChillMainBundle:Center', - 'query_builder' => function(EntityRepository $er) use ($centers) { + $centers = $this->authorizationHelper->getReachableCenters( + $this->user, + $export->requiredRole() + ); + + $builder->add(self::CENTERS_IDENTIFIERS, EntityType::class, [ + 'class' => 'ChillMainBundle:Center', + 'query_builder' => function (EntityRepository $er) use ($centers) { $qb = $er->createQueryBuilder('c'); - $ids = array_map(function(Center $el) { return $el->getId(); }, - $centers); + $ids = array_map( + function (Center $el) { + return $el->getId(); + }, + $centers + ); + return $qb->where($qb->expr()->in('c.id', $ids)); - }, - 'multiple' => true, - 'expanded' => true, - 'choice_label' => function(Center $c) { return $c->getName(); }, - 'data' => count($this->groupingCenters) > 0 ? null : $centers - )); - + }, + 'multiple' => true, + 'expanded' => true, + 'choice_label' => function (Center $c) { + return $c->getName(); + }, + 'data' => count($this->groupingCenters) > 0 ? null : $centers, + ]); + if (count($this->groupingCenters) > 0) { $groupingBuilder = $builder->create('g', null, [ - 'compound' => true + 'compound' => true, ]); foreach ($this->groupingCenters as $key => $gc) { $choices = $this->buildChoices($centers, $gc); - + if (count($choices) > 0) { $groupingBuilder->add($key, ChoiceType::class, [ 'choices' => $choices, 'multiple' => true, 'expanded' => true, 'label' => $gc->getName(), - 'required' => false + 'required' => false, ]); } } - + if ($groupingBuilder->count() > 0) { $builder->add($groupingBuilder); } } - + $builder->addModelTransformer(new CallbackTransformer( - function($data) use ($centers) { return $this->transform($data, $centers); }, - function($data) use ($centers) { return $this->reverseTransform($data, $centers); } - )); + function ($data) use ($centers) { + return $this->transform($data, $centers); + }, + function ($data) use ($centers) { + return $this->reverseTransform($data, $centers); + } + )); } - - public function addGroupingCenter(GroupingCenterInterface $grouping) + + public function configureOptions(OptionsResolver $resolver) { - $this->groupingCenters[md5($grouping->getName())] = $grouping; + $resolver->setRequired('export_alias'); } - + protected function buildChoices($reachablesCenters, GroupingCenterInterface $gc) { $result = []; - + foreach ($gc->getGroups() as $group) { foreach ($gc->getCentersForGroup($group) as $center) { - if (\in_array($center, $reachablesCenters)) { + if (in_array($center, $reachablesCenters)) { $result[$group] = $group; } } } - + return $result; } - + + protected function reverseTransform($data, $centers) + { + $picked = $data[self::CENTERS_IDENTIFIERS] + instanceof \Doctrine\Common\Collections\Collection ? + $data[self::CENTERS_IDENTIFIERS]->toArray() + : + $data[self::CENTERS_IDENTIFIERS]; + + if (array_key_exists('g', $data)) { + foreach ($data['g'] as $gcid => $group) { + $picked = + array_merge( + array_intersect( + $this->groupingCenters[$gcid]->getCentersForGroup($group), + $centers + ), + $picked + ); + } + } + + return array_unique($picked); + } + protected function transform($data, $centers) { return $data; } - - protected function reverseTransform($data, $centers) - { - $picked = $data[self::CENTERS_IDENTIFIERS] - instanceof \Doctrine\Common\Collections\Collection ? - $data[self::CENTERS_IDENTIFIERS]->toArray() - : - $data[self::CENTERS_IDENTIFIERS]; - - if (\array_key_exists('g', $data)) { - foreach($data['g'] as $gcid => $group) { - $picked = - \array_merge( - \array_intersect( - $this->groupingCenters[$gcid] ->getCentersForGroup($group), - $centers - ), - $picked - ) - ; - } - } - - return \array_unique($picked); - } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php index 44726d915..998d4775c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickFormatterType.php @@ -1,36 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type\Export; +use Chill\MainBundle\Export\ExportManager; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; - -use Chill\MainBundle\Export\ExportManager; /** - * Choose a formatter amongst the available formatters - * - * - * @author Julien Fastré + * Choose a formatter amongst the available formatters. */ class PickFormatterType extends AbstractType { @@ -45,26 +31,26 @@ class PickFormatterType extends AbstractType { $export = $this->exportManager->getExport($options['export_alias']); $allowedFormatters = $this->exportManager - ->getFormattersByTypes($export->getAllowedFormattersTypes()); + ->getFormattersByTypes($export->getAllowedFormattersTypes()); //build choices - $choices = array(); - foreach($allowedFormatters as $alias => $formatter) { + $choices = []; + + foreach ($allowedFormatters as $alias => $formatter) { $choices[$formatter->getName()] = $alias; } - $builder->add('alias', ChoiceType::class, array( + $builder->add('alias', ChoiceType::class, [ 'choices' => $choices, 'multiple' => false, - 'placeholder' => 'Choose a format' - )); + 'placeholder' => 'Choose a format', + ]); //$builder->get('type')->addModelTransformer($transformer); } public function configureOptions(OptionsResolver $resolver) { - $resolver->setRequired(array('export_alias')); + $resolver->setRequired(['export_alias']); } - } diff --git a/src/Bundle/ChillMainBundle/Form/Type/PostalCodeType.php b/src/Bundle/ChillMainBundle/Form/Type/PostalCodeType.php index 1c1242a5a..0e80345af 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/PostalCodeType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/PostalCodeType.php @@ -1,67 +1,50 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\MainBundle\Entity\PostalCode; +use Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader; use Symfony\Component\Translation\TranslatorInterface; /** - * A form to pick between PostalCode - * - * @author Julien Fastré - * @author Champs Libres + * A form to pick between PostalCode. */ class PostalCodeType extends AbstractType { /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * - * @var UrlGeneratorInterface - */ - protected $urlGenerator; - - /** - * * @var PostalCodeChoiceLoader */ protected $choiceLoader; - + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + /** - * * @var TranslatorInterface */ protected $translator; + /** + * @var UrlGeneratorInterface + */ + protected $urlGenerator; + public function __construct( TranslatableStringHelper $helper, UrlGeneratorInterface $urlGenerator, @@ -74,27 +57,6 @@ class PostalCodeType extends AbstractType $this->translator = $translator; } - - public function getParent() - { - return EntityType::class; - } - - public function configureOptions(OptionsResolver $resolver) - { - // create a local copy for usage in Closure - $helper = $this->translatableStringHelper; - $resolver - ->setDefault('class', PostalCode::class) - ->setDefault('choice_label', function(PostalCode $code) use ($helper) { - return $code->getCode().' '.$code->getName().' ['. - $helper->localize($code->getCountry()->getName()).']'; - }) - ->setDefault('choice_loader', $this->choiceLoader) - ->setDefault('placeholder', 'Select a postal code') - ; - } - public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['attr']['data-postal-code'] = 'data-postal-code'; @@ -107,4 +69,22 @@ class PostalCodeType extends AbstractType $view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching'); } + public function configureOptions(OptionsResolver $resolver) + { + // create a local copy for usage in Closure + $helper = $this->translatableStringHelper; + $resolver + ->setDefault('class', PostalCode::class) + ->setDefault('choice_label', function (PostalCode $code) use ($helper) { + return $code->getCode() . ' ' . $code->getName() . ' [' . + $helper->localize($code->getCountry()->getName()) . ']'; + }) + ->setDefault('choice_loader', $this->choiceLoader) + ->setDefault('placeholder', 'Select a postal code'); + } + + public function getParent() + { + return EntityType::class; + } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php index 379bb2183..6e0719ba8 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php @@ -1,19 +1,10 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; @@ -36,6 +27,8 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; +use function array_map; + /** * Allow to pick amongst available scope for the current * user. @@ -44,8 +37,6 @@ use Symfony\Component\Security\Core\Role\Role; * * - `center`: the center of the entity * - `role` : the role of the user - * - * @author Julien Fastré */ class ScopePickerType extends AbstractType { @@ -54,16 +45,16 @@ class ScopePickerType extends AbstractType */ protected $authorizationHelper; - /** - * @var TokenStorageInterface - */ - protected $tokenStorage; - /** * @var EntityRepository */ protected $scopeRepository; + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + /** * @var TranslatableStringHelper */ @@ -109,7 +100,8 @@ class ScopePickerType extends AbstractType public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars = array_replace( - $view->vars, [ + $view->vars, + [ 'hideLabel' => true, ] ); @@ -146,7 +138,8 @@ class ScopePickerType extends AbstractType // role constraints ->andWhere($qb->expr()->in('rs.role', ':roles')) ->setParameter( - 'roles', \array_map( + 'roles', + array_map( function (Role $role) { return $role->getRole(); }, @@ -154,8 +147,8 @@ class ScopePickerType extends AbstractType ) ) // user contraint - ->andWhere(':user MEMBER OF gc.users') - ->setParameter('user', $this->tokenStorage->getToken()->getUser()); + ->andWhere(':user MEMBER OF gc.users') + ->setParameter('user', $this->tokenStorage->getToken()->getUser()); return $qb; } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2ChoiceType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2ChoiceType.php index faadb3154..bd02fbd3f 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2ChoiceType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2ChoiceType.php @@ -1,36 +1,32 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Extends choice to allow adding select2 library on widget - * - * @author Julien Fastré + * Extends choice to allow adding select2 library on widget. */ class Select2ChoiceType extends AbstractType { + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults( + [ + 'attr' => ['class' => 'select2 '], + ] + ); + } + public function getBlockPrefix() { return 'select2_choice'; @@ -40,12 +36,4 @@ class Select2ChoiceType extends AbstractType { return ChoiceType::class; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - array( - 'attr' => array('class' => 'select2 '), - )); - } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php index 617d1afce..5b8233575 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2CountryType.php @@ -1,49 +1,28 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; -use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Extends choice to allow adding select2 library on widget - * - * @author Julien Fastré - * @author Marc Ducobu + * Extends choice to allow adding select2 library on widget. */ class Select2CountryType extends AbstractType { /** - * @var RequestStack - */ - private $requestStack; - - /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; @@ -53,38 +32,32 @@ class Select2CountryType extends AbstractType */ private $em; + /** + * @var RequestStack + */ + private $requestStack; + public function __construct( RequestStack $requestStack, ObjectManager $em, TranslatableStringHelper $translatableStringHelper - ) - { + ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; } - public function getBlockPrefix() - { - return 'select2_chill_country'; - } - public function buildForm(FormBuilderInterface $builder, array $options) { - $transformer = new ObjectToIdTransformer($this->em,'Chill\MainBundle\Entity\Country'); + $transformer = new ObjectToIdTransformer($this->em, 'Chill\MainBundle\Entity\Country'); $builder->addModelTransformer($transformer); } - public function getParent() - { - return Select2ChoiceType::class; - } - public function configureOptions(OptionsResolver $resolver) { $locale = $this->requestStack->getCurrentRequest()->getLocale(); $countries = $this->em->getRepository('Chill\MainBundle\Entity\Country')->findAll(); - $choices = array(); + $choices = []; foreach ($countries as $c) { $choices[$c->getId()] = $this->translatableStringHelper->localize($c->getName()); @@ -92,9 +65,19 @@ class Select2CountryType extends AbstractType asort($choices, SORT_STRING | SORT_FLAG_CASE); - $resolver->setDefaults(array( - 'class' => 'Chill\MainBundle\Entity\Country', - 'choices' => array_combine(array_values($choices),array_keys($choices)) - )); + $resolver->setDefaults([ + 'class' => 'Chill\MainBundle\Entity\Country', + 'choices' => array_combine(array_values($choices), array_keys($choices)), + ]); + } + + public function getBlockPrefix() + { + return 'select2_chill_country'; + } + + public function getParent() + { + return Select2ChoiceType::class; } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2EntityType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2EntityType.php index e72bf0d8e..9392b2a8c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2EntityType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2EntityType.php @@ -1,36 +1,30 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; /** - * Extends choice to allow adding select2 library on widget - * - * @author Julien Fastré + * Extends choice to allow adding select2 library on widget. */ class Select2EntityType extends AbstractType { + public function configureOptions(OptionsResolver $resolver) + { + $resolver->replaceDefaults( + ['attr' => ['class' => 'select2 ']] + ); + } + public function getBlockPrefix() { return 'select2_entity'; @@ -40,11 +34,4 @@ class Select2EntityType extends AbstractType { return EntityType::class; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver->replaceDefaults( - array('attr' => array('class' => 'select2 ')) - ); - } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php b/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php index 2c8dea857..97ba9ae38 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Select2LanguageType.php @@ -1,43 +1,31 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Form\FormBuilderInterface; use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer; -use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Form\Type\Select2ChoiceType; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * Extends choice to allow adding select2 library on widget for languages (multiple) + * Extends choice to allow adding select2 library on widget for languages (multiple). */ class Select2LanguageType extends AbstractType { /** - * @var RequestStack + * @var TranslatableStringHelper */ - private $requestStack; + protected $translatableStringHelper; /** * @var ObjectManager @@ -45,43 +33,31 @@ class Select2LanguageType extends AbstractType private $em; /** - * - * @var TranslatableStringHelper + * @var RequestStack */ - protected $translatableStringHelper; + private $requestStack; public function __construct( RequestStack $requestStack, ObjectManager $em, TranslatableStringHelper $translatableStringHelper - ) - { + ) { $this->requestStack = $requestStack; $this->em = $em; $this->translatableStringHelper = $translatableStringHelper; } - public function getBlockPrefix() - { - return 'select2_chill_language'; - } - public function buildForm(FormBuilderInterface $builder, array $options) { - $transformer = new MultipleObjectsToIdTransformer($this->em,'Chill\MainBundle\Entity\Language'); + $transformer = new MultipleObjectsToIdTransformer($this->em, 'Chill\MainBundle\Entity\Language'); $builder->addModelTransformer($transformer); } - public function getParent() - { - return Select2ChoiceType::class; - } - public function configureOptions(OptionsResolver $resolver) { $locale = $this->requestStack->getCurrentRequest()->getLocale(); $languages = $this->em->getRepository('Chill\MainBundle\Entity\Language')->findAll(); - $choices = array(); + $choices = []; foreach ($languages as $l) { $choices[$l->getId()] = $this->translatableStringHelper->localize($l->getName()); @@ -89,9 +65,19 @@ class Select2LanguageType extends AbstractType asort($choices, SORT_STRING | SORT_FLAG_CASE); - $resolver->setDefaults(array( - 'class' => 'Chill\MainBundle\Entity\Language', - 'choices' => array_combine(array_values($choices),array_keys($choices)) - )); + $resolver->setDefaults([ + 'class' => 'Chill\MainBundle\Entity\Language', + 'choices' => array_combine(array_values($choices), array_keys($choices)), + ]); + } + + public function getBlockPrefix() + { + return 'select2_chill_language'; + } + + public function getParent() + { + return Select2ChoiceType::class; } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/TranslatableStringFormType.php b/src/Bundle/ChillMainBundle/Form/Type/TranslatableStringFormType.php index 18a0a6e9f..3a5f8c8fb 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/TranslatableStringFormType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/TranslatableStringFormType.php @@ -1,5 +1,12 @@ availableLanguages = $availableLanguages; $this->frameworkTranslatorFallback = $translator->getFallbackLocales(); } - public function buildForm(FormBuilderInterface $builder, array $options) { + public function buildForm(FormBuilderInterface $builder, array $options) + { foreach ($this->availableLanguages as $lang) { - $builder->add($lang, TextType::class, - array('required' => (in_array($lang, - $this->frameworkTranslatorFallback)))); + $builder->add( + $lang, + TextType::class, + ['required' => (in_array( + $lang, + $this->frameworkTranslatorFallback + ))] + ); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php b/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php index a179f4740..347991cc1 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php @@ -1,34 +1,24 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\AbstractType; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Doctrine\ORM\EntityRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Role\Role; - /** * Pick a user available for the given role and center. * @@ -36,25 +26,20 @@ use Symfony\Component\Security\Core\Role\Role; * * - `role` : the role the user can reach * - `center`: the center a user can reach - * - * @author Julien Fastré */ class UserPickerType extends AbstractType { /** - * * @var AuthorizationHelper */ protected $authorizationHelper; /** - * * @var TokenStorageInterface */ protected $tokenStorage; /** - * * @var \Chill\MainBundle\Repository\UserRepository */ protected $userRepository; @@ -69,40 +54,35 @@ class UserPickerType extends AbstractType $this->userRepository = $userRepository; } - public function configureOptions(OptionsResolver $resolver) { $resolver // create `center` option ->setRequired('center') - ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class ]) + ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class]) // create ``role` option ->setRequired('role') - ->setAllowedTypes('role', ['string', \Symfony\Component\Security\Core\Role\Role::class ]) - ; + ->setAllowedTypes('role', ['string', \Symfony\Component\Security\Core\Role\Role::class]); $resolver ->setDefault('having_permissions_group_flag', null) ->setAllowedTypes('having_permissions_group_flag', ['string', 'null']) ->setDefault('class', User::class) ->setDefault('placeholder', 'Choose an user') - ->setDefault('choice_label', function(User $u) { + ->setDefault('choice_label', function (User $u) { return $u->getUsername(); }) - ->setNormalizer('choices', function(Options $options) { - + ->setNormalizer('choices', function (Options $options) { $users = $this->authorizationHelper ->findUsersReaching($options['role'], $options['center']); - - if (NULL !== $options['having_permissions_group_flag']) { + + if (null !== $options['having_permissions_group_flag']) { return $this->userRepository - ->findUsersHavingFlags($options['having_permissions_group_flag'], $users) - ; + ->findUsersHavingFlags($options['having_permissions_group_flag'], $users); } - + return $users; - }) - ; + }); } public function getParent() diff --git a/src/Bundle/ChillMainBundle/Form/UserPasswordType.php b/src/Bundle/ChillMainBundle/Form/UserPasswordType.php index 4486b5643..3a88d5d6b 100644 --- a/src/Bundle/ChillMainBundle/Form/UserPasswordType.php +++ b/src/Bundle/ChillMainBundle/Form/UserPasswordType.php @@ -1,104 +1,102 @@ passwordEncoder = $passwordEncoder; $this->chillLogger = $chillLogger; } - - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('new_password', RepeatedType::class, array( + ->add('new_password', RepeatedType::class, [ 'type' => PasswordType::class, 'required' => false, - 'options' => array(), - 'first_options' => array( - 'label' => 'Password' - ), - 'second_options' => array( - 'label' => 'Repeat the password' - ), - 'invalid_message' => "The password fields must match", - 'constraints' => array( - new Length(array( + 'options' => [], + 'first_options' => [ + 'label' => 'Password', + ], + 'second_options' => [ + 'label' => 'Repeat the password', + ], + 'invalid_message' => 'The password fields must match', + 'constraints' => [ + new Length([ 'min' => 9, - 'minMessage' => 'The password must be greater than {{ limit }} characters' - )), + 'minMessage' => 'The password must be greater than {{ limit }} characters', + ]), new NotBlank(), - new Regex(array( - 'pattern' => "/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%!,;:+\"'-\/{}~=µ\(\)£]).{6,})/", - 'message' => "The password must contains one letter, one " - . "capitalized letter, one number and one special character " - . "as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed." - )) - ) - )) + new Regex([ + 'pattern' => "/((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%!,;:+\"'-\\/{}~=µ\\(\\)£]).{6,})/", + 'message' => 'The password must contains one letter, one ' + . 'capitalized letter, one number and one special character ' + . "as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed.", + ]), + ], + ]) ->add('actual_password', PasswordType::class, [ 'label' => 'Your actual password', 'mapped' => false, 'constraints' => [ new Callback([ - 'callback' => function($password, ExecutionContextInterface $context, $payload) use ($options) { - if (TRUE === $this->passwordEncoder->isPasswordValid($options['user'], $password)) { + 'callback' => function ($password, ExecutionContextInterface $context, $payload) use ($options) { + if (true === $this->passwordEncoder->isPasswordValid($options['user'], $password)) { return; } - + // password problem :-) $this->chillLogger - ->notice("incorrect password when trying to change password", [ - 'username' => $options['user']->getUsername() + ->notice('incorrect password when trying to change password', [ + 'username' => $options['user']->getUsername(), ]); $context->addViolation('Incorrect password'); - } - ]) - ] - ]) - ; + }, + ]), + ], + ]); } - + public function configureOptions(OptionsResolver $resolver) { $resolver ->setRequired('user') - ->setAllowedTypes('user', \Chill\MainBundle\Entity\User::class) - ; + ->setAllowedTypes('user', \Chill\MainBundle\Entity\User::class); } /** diff --git a/src/Bundle/ChillMainBundle/Form/UserType.php b/src/Bundle/ChillMainBundle/Form/UserType.php index 5196ee6c0..ac8908974 100644 --- a/src/Bundle/ChillMainBundle/Form/UserType.php +++ b/src/Bundle/ChillMainBundle/Form/UserType.php @@ -1,70 +1,71 @@ add('username') - ->add('email') - ; + ->add('email'); + if ($options['is_creation']) { - $builder->add('plainPassword', RepeatedType::class, array( + $builder->add('plainPassword', RepeatedType::class, [ 'mapped' => false, 'type' => PasswordType::class, 'required' => false, - 'options' => array(), - 'first_options' => array( - 'label' => 'Password' - ), - 'second_options' => array( - 'label' => 'Repeat the password' - ), - 'invalid_message' => "The password fields must match", - 'constraints' => array( - new Length(array( + 'options' => [], + 'first_options' => [ + 'label' => 'Password', + ], + 'second_options' => [ + 'label' => 'Repeat the password', + ], + 'invalid_message' => 'The password fields must match', + 'constraints' => [ + new Length([ 'min' => 9, - 'minMessage' => 'The password must be greater than {{ limit }} characters' - )), + 'minMessage' => 'The password must be greater than {{ limit }} characters', + ]), new NotBlank(), - new Regex(array( - 'pattern' => "/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%!,;:+\"'-\/{}~=µ\(\)£]).{6,})/", - 'message' => "The password must contains one letter, one " - . "capitalized letter, one number and one special character " - . "as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed." - )) - ) - )); - + new Regex([ + 'pattern' => "/((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%!,;:+\"'-\\/{}~=µ\\(\\)£]).{6,})/", + 'message' => 'The password must contains one letter, one ' + . 'capitalized letter, one number and one special character ' + . "as *[@#$%!,;:+\"'-/{}~=µ()£]). Other characters are allowed.", + ]), + ], + ]); } else { - $builder->add($builder - ->create('enabled', ChoiceType::class, array( - 'choices' => array( + $builder->add( + $builder + ->create('enabled', ChoiceType::class, [ + 'choices' => [ 'Disabled, the user is not allowed to login' => 0, - 'Enabled, the user is active' => 1 - ), + 'Enabled, the user is active' => 1, + ], 'expanded' => false, 'multiple' => false, - )) - ); + ]) + ); } } @@ -73,14 +74,13 @@ class UserType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\MainBundle\Entity\User' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\MainBundle\Entity\User', + ]); $resolver - ->setDefaults(array('is_creation' => false)) - ->addAllowedValues('is_creation', array(true, false)) - ; + ->setDefaults(['is_creation' => false]) + ->addAllowedValues('is_creation', [true, false]); } /** diff --git a/src/Bundle/ChillMainBundle/Form/Utils/PermissionsGroupFlagProvider.php b/src/Bundle/ChillMainBundle/Form/Utils/PermissionsGroupFlagProvider.php index 39ddb62d5..0f7bb23b9 100644 --- a/src/Bundle/ChillMainBundle/Form/Utils/PermissionsGroupFlagProvider.php +++ b/src/Bundle/ChillMainBundle/Form/Utils/PermissionsGroupFlagProvider.php @@ -1,17 +1,19 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Notification; use Chill\MainBundle\Entity\User; use Psr\Log\LoggerInterface; -use Symfony\Component\Mailer\MailerInterface; +use Swift_Mailer; +use Swift_Message; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Translation\TranslatorInterface; use Twig\Environment; +use function call_user_func; + /** * Class Mailer * Classe d'aide pour l'envoi de notification. - * - * Héberge toutes les méthodes pour ré-écrire les URL en fonction de la langue de l'utilisateur. * - * @package Chill\MainBundle\Notification + * Héberge toutes les méthodes pour ré-écrire les URL en fonction de la langue de l'utilisateur. */ class Mailer { + /** + * @var Swift_Mailer + */ + protected $forcedMailer; + /** * @var LoggerInterface */ protected $logger; - + /** - * @var \Twig\Environment - */ - protected $twig; - - /** - * @var \Swift_Mailer + * @var Swift_Mailer */ protected $mailer; - - /** - * @var \Swift_Mailer - */ - protected $forcedMailer; - - /** - * @var RouterInterface - */ - protected $router; - - /** - * @var TranslatorInterface - */ - protected $translator; - + /** * @var array */ protected $routeParameters; - + + /** + * @var RouterInterface + */ + protected $router; + + /** + * @var TranslatorInterface + */ + protected $translator; + + /** + * @var \Twig\Environment + */ + protected $twig; + /** * Mailer constructor. * - * @param LoggerInterface $logger - * @param Environment $twig - * @param \Swift_Mailer $mailer - * @param RouterInterface $router - * @param TranslatorInterface $translator * @param $routeParameters */ public function __construct( - LoggerInterface $logger, + LoggerInterface $logger, Environment $twig, - \Swift_Mailer $mailer, + Swift_Mailer $mailer, // due to bug https://github.com/symfony/swiftmailer-bundle/issues/127 // \Swift_Transport $mailerTransporter, RouterInterface $router, - TranslatorInterface $translator, + TranslatorInterface $translator, $routeParameters ) { $this->logger = $logger; @@ -97,60 +85,40 @@ class Mailer $this->translator = $translator; $this->routeParameters = $routeParameters; } - + /** - * Envoie une notification à un utilisateur. - * - * @param \User $to - * @param array $subject Subject of the message [ 0 => $message (required), 1 => $parameters (optional), 3 => $domain (optional) ] - * @param array $bodies The bodies. An array where keys are the contentType and values the bodies - * @param callable $callback a callback to customize the message (add attachment, etc.) + * @param $template + * + * @throws \Twig\Error\LoaderError + * @throws \Twig\Error\RuntimeError + * @throws \Twig\Error\SyntaxError + * + * @return string */ - public function sendNotification( - $recipient, - array $subject, - array $bodies, - callable $callback = null, - $force = false - ) + public function renderContentToUser(User $to, $template, array $parameters = []) { - $fromEmail = $this->routeParameters['from_email']; - $fromName = $this->routeParameters['from_name']; - $to = $recipient instanceof User ? $recipient->getEmail() : $recipient; - - $subjectI18n = $this->translator->trans( - $subject[0], - $subject[1] ?? [], - $subject[2] ?? null - ); - - $message = (new \Swift_Message($subjectI18n)) - ->setFrom($fromEmail, $fromName) - ->setTo($to) - ; - - foreach ($bodies as $contentType => $content) { - $message->setBody($content, $contentType); - } - - if ($callback !== null) { - \call_user_func($callback, $message); - } - - $this->logger->info("[notification] Sending notification", [ - 'to' => $message->getTo(), - 'subject' => $message->getSubject() - ]); - - $this->sendMessage($message, $force); + $context = $this->router->getContext(); + $previousHost = $context->getHost(); + $previousScheme = $context->getScheme(); + + $context->setHost($this->routeParameters['host']); + $context->setScheme($this->routeParameters['scheme']); + + $content = $this->twig->render($template, $parameters); + + // reset the host + $context->setHost($previousHost); + $context->setScheme($previousScheme); + + return $content; } - + /** - * @param \Swift_Message $message * @param $force + * * @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface */ - public function sendMessage(\Swift_Message $message, $force) + public function sendMessage(Swift_Message $message, $force) { if ($force) { $this->forcedMailer->send($message); @@ -158,31 +126,50 @@ class Mailer $this->mailer->send($message); } } - + /** - * @param User $to - * @param $template - * @param array $parameters - * @return string - * @throws \Twig\Error\LoaderError - * @throws \Twig\Error\RuntimeError - * @throws \Twig\Error\SyntaxError + * Envoie une notification à un utilisateur. + * + * @param array $subject Subject of the message [ 0 => $message (required), 1 => $parameters (optional), 3 => $domain (optional) ] + * @param array $bodies The bodies. An array where keys are the contentType and values the bodies + * @param callable $callback a callback to customize the message (add attachment, etc.) + * @param mixed $recipient + * @param mixed $force */ - public function renderContentToUser(User $to, $template, array $parameters = array()) - { - $context = $this->router->getContext(); - $previousHost = $context->getHost(); - $previousScheme = $context->getScheme(); - - $context->setHost($this->routeParameters['host']); - $context->setScheme($this->routeParameters['scheme']); - - $content = $this->twig->render($template, $parameters); - - // reset the host - $context->setHost($previousHost); - $context->setScheme($previousScheme); - - return $content; + public function sendNotification( + $recipient, + array $subject, + array $bodies, + ?callable $callback = null, + $force = false + ) { + $fromEmail = $this->routeParameters['from_email']; + $fromName = $this->routeParameters['from_name']; + $to = $recipient instanceof User ? $recipient->getEmail() : $recipient; + + $subjectI18n = $this->translator->trans( + $subject[0], + $subject[1] ?? [], + $subject[2] ?? null + ); + + $message = (new Swift_Message($subjectI18n)) + ->setFrom($fromEmail, $fromName) + ->setTo($to); + + foreach ($bodies as $contentType => $content) { + $message->setBody($content, $contentType); + } + + if (null !== $callback) { + call_user_func($callback, $message); + } + + $this->logger->info('[notification] Sending notification', [ + 'to' => $message->getTo(), + 'subject' => $message->getSubject(), + ]); + + $this->sendMessage($message, $force); } } diff --git a/src/Bundle/ChillMainBundle/Pagination/ChillPaginationTwig.php b/src/Bundle/ChillMainBundle/Pagination/ChillPaginationTwig.php index 4917216a1..6ea40fc67 100644 --- a/src/Bundle/ChillMainBundle/Pagination/ChillPaginationTwig.php +++ b/src/Bundle/ChillMainBundle/Pagination/ChillPaginationTwig.php @@ -1,23 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; @@ -27,54 +14,56 @@ use Twig\Extension\AbstractExtension; use Twig\TwigFunction; /** - * add twig function to render pagination - * - * @author Julien Fastré - * @author Champs Libres + * add twig function to render pagination. */ class ChillPaginationTwig extends AbstractExtension { - const LONG_TEMPLATE = '@ChillMain/Pagination/long.html.twig'; - const SHORT_TEMPLATE = '@ChillMain/Pagination/short.html.twig'; - + public const LONG_TEMPLATE = '@ChillMain/Pagination/long.html.twig'; + + public const SHORT_TEMPLATE = '@ChillMain/Pagination/short.html.twig'; + + public function getFunctions() + { + return [ + new TwigFunction( + 'chill_pagination', + [$this, 'paginationRender'], + [ + 'needs_environment' => true, + 'is_safe' => ['html'], + ] + ), + ]; + } + public function getName() { return 'chill_pagination'; } - - public function getFunctions() - { - return array( - new TwigFunction( - 'chill_pagination', - array($this, 'paginationRender'), - array( - 'needs_environment' => true, - 'is_safe' => ['html'] - ) - ) - ); - } - + public function paginationRender( - Environment $env, - PaginatorInterface $paginator, - $template = '@ChillMain/Pagination/long.html.twig' + Environment $env, + PaginatorInterface $paginator, + $template = '@ChillMain/Pagination/long.html.twig' ) { switch ($template) { case 'long': $t = self::LONG_TEMPLATE; + break; + case 'short': $t = self::SHORT_TEMPLATE; + break; + default: $t = $template; } - - return $env->render($t, array( - 'paginator' => $paginator, - 'current' => $paginator->getCurrentPage()->getNumber() - )); + + return $env->render($t, [ + 'paginator' => $paginator, + 'current' => $paginator->getCurrentPage()->getNumber(), + ]); } } diff --git a/src/Bundle/ChillMainBundle/Pagination/Page.php b/src/Bundle/ChillMainBundle/Pagination/Page.php index e6b3943ed..5bac58327 100644 --- a/src/Bundle/ChillMainBundle/Pagination/Page.php +++ b/src/Bundle/ChillMainBundle/Pagination/Page.php @@ -1,21 +1,10 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; @@ -23,62 +12,57 @@ namespace Chill\MainBundle\Pagination; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** - * a page is an element of a pagination - * - * @author Julien Fastré - * @author Champs Libres + * a page is an element of a pagination. */ class Page implements PageInterface { /** - * - * @var UrlGeneratorInterface - */ - protected $urlGenerator; - - /** - * the number of the current page - * - * @var int - */ - protected $number; - - /** - * The route for the current page - * - * @var string - */ - protected $route; - - /** - * Parameters for the route to the current page - * - * @var array - */ - protected $routeParameters; - - /** - * the number of item per page + * the number of item per page. * * @var int */ protected $itemPerPage; - + /** - * The number of items in the whole iteration + * the number of the current page. + * + * @var int + */ + protected $number; + + /** + * The route for the current page. + * + * @var string + */ + protected $route; + + /** + * Parameters for the route to the current page. + * + * @var array + */ + protected $routeParameters; + + /** + * The number of items in the whole iteration. * * @var int */ protected $totalItems; + /** + * @var UrlGeneratorInterface + */ + protected $urlGenerator; public function __construct( - $number, - $itemPerPage, - UrlGeneratorInterface $urlGenerator, - $route, - array $routeParameters, - $totalItems + $number, + $itemPerPage, + UrlGeneratorInterface $urlGenerator, + $route, + array $routeParameters, + $totalItems ) { $this->urlGenerator = $urlGenerator; $this->number = $number; @@ -87,7 +71,7 @@ class Page implements PageInterface $this->routeParameters = $routeParameters; $this->totalItems = $totalItems; } - + public function generateUrl() { return $this->urlGenerator->generate($this->route, $this->routeParameters); @@ -101,7 +85,7 @@ class Page implements PageInterface public function getLastItemNumber() { $last = $this->number * $this->itemPerPage - 1; - + return $last < $this->totalItems ? $last : $this->totalItems; } @@ -109,5 +93,4 @@ class Page implements PageInterface { return $this->number; } - } diff --git a/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php b/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php index 26add87fa..b67f24d8c 100644 --- a/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php +++ b/src/Bundle/ChillMainBundle/Pagination/PageGenerator.php @@ -1,50 +1,36 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; +use Iterator; + /** - * PageGenerator associated with a Paginator - * - * @author Julien Fastré - * @author Champs Libres + * PageGenerator associated with a Paginator. */ -class PageGenerator implements \Iterator +class PageGenerator implements Iterator { /** - * - * @var Paginator - */ - protected $paginator; - - /** - * * @var int */ protected $current = 1; - - public function __construct(Paginator $paginator) + + /** + * @var Paginator + */ + protected $paginator; + + public function __construct(Paginator $paginator) { - $this->paginator = $paginator;; + $this->paginator = $paginator; } - + public function current() { return $this->paginator->getPage($current); @@ -57,7 +43,7 @@ class PageGenerator implements \Iterator public function next() { - $this->current++; + ++$this->current; } public function rewind() @@ -67,7 +53,7 @@ class PageGenerator implements \Iterator public function valid() { - return $this->current > 0 - && $this->current <= $this->paginator->countPages(); + return 0 < $this->current + && $this->paginator->countPages() >= $this->current; } } diff --git a/src/Bundle/ChillMainBundle/Pagination/PageInterface.php b/src/Bundle/ChillMainBundle/Pagination/PageInterface.php index aa87c289c..ea6b841a7 100644 --- a/src/Bundle/ChillMainBundle/Pagination/PageInterface.php +++ b/src/Bundle/ChillMainBundle/Pagination/PageInterface.php @@ -1,43 +1,29 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; /** - * Represents a page included in a pagination - * - * @author Julien Fastré + * Represents a page included in a pagination. */ interface PageInterface { public function generateUrl(); - + + public function getFirstItemNumber(); + + public function getLastItemNumber(); + /** * get the page number. - * - * The first page number is 1. + * + * The first page number is 1. */ public function getNumber(); - - public function getFirstItemNumber(); - - public function getLastItemNumber(); - } diff --git a/src/Bundle/ChillMainBundle/Pagination/Paginator.php b/src/Bundle/ChillMainBundle/Pagination/Paginator.php index 82577d078..3599a9257 100644 --- a/src/Bundle/ChillMainBundle/Pagination/Paginator.php +++ b/src/Bundle/ChillMainBundle/Pagination/Paginator.php @@ -1,104 +1,90 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; +use RuntimeException; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; - /** * Standard paginator class. * * Represent a set of paginated pages; - * - * @author Julien Fastré - * @author Champs Libres */ class Paginator implements PaginatorInterface { /** - * The number of total items - * - * @var int - */ - protected $totalItems; - - /** - * the number of items on a single page - * - * @var int - */ - protected $itemPerPage; - /** - * The number of the current page + * The number of the current page. * * @var int */ protected $currentPageNumber; - + /** - * the route of the pages + * the number of items on a single page. * - * @var string + * @var int */ - protected $route; - + protected $itemPerPage; + /** - * the parameters of the route - * - * @var string[] - */ - protected $routeParameters; - - /** - * the generator for url - * - * @var UrlGeneratorInterface - */ - protected $urlGenerator; - - /** - * the key in the GET parameter to indicate the page number in - * generated routes - * - * @var string - */ - protected $pageKey; - - /** - * the key in the GET parameter to indicate the number of item per page + * the key in the GET parameter to indicate the number of item per page. * * @var string */ protected $itemPerPageKey; + /** + * the key in the GET parameter to indicate the page number in + * generated routes. + * + * @var string + */ + protected $pageKey; + + /** + * the route of the pages. + * + * @var string + */ + protected $route; + + /** + * the parameters of the route. + * + * @var string[] + */ + protected $routeParameters; + + /** + * The number of total items. + * + * @var int + */ + protected $totalItems; + + /** + * the generator for url. + * + * @var UrlGeneratorInterface + */ + protected $urlGenerator; public function __construct( - $totalItems, - $itemPerPage, - $currentPageNumber, - $route, - array $routeParameters, - UrlGeneratorInterface $urlGenerator, - $pageKey, - $itemPerPageKey + $totalItems, + $itemPerPage, + $currentPageNumber, + $route, + array $routeParameters, + UrlGeneratorInterface $urlGenerator, + $pageKey, + $itemPerPageKey ) { $this->totalItems = $totalItems; $this->itemPerPage = $itemPerPage; @@ -115,8 +101,18 @@ class Paginator implements PaginatorInterface return $this->countPages(); } + public function countPages() + { + $nb = floor($this->totalItems / $this->itemPerPage); + + if ($this->totalItems % $this->itemPerPage > 0) { + ++$nb; + } + + return 0 == $nb ? 1 : (int) $nb; + } + /** - * * @return \Chill\MainBundle\Pagination\Page */ public function getCurrentPage() @@ -128,68 +124,78 @@ class Paginator implements PaginatorInterface { return $this->getCurrentPage()->getFirstItemNumber(); } - - public function isCurrentPage(PageInterface $page) - { - return $page->getNumber() === $this->currentPageNumber; - } - public function getItemsPerPage() + public function getItemsPerPage() { return $this->itemPerPage; } - - public function setItemsPerPage($itemPerPage) - { - $this->itemPerPage = $itemPerPage; - } - - public function getTotalItems() - { - return $this->totalItems; - } - - public function countPages() - { - $nb = floor($this->totalItems / $this->itemPerPage); - - if ($this->totalItems % $this->itemPerPage > 0) { - $nb++; - } - - return $nb == 0 ? 1 : (int) $nb; - } /** + * @throws RuntimeException if the next page does not exists * * @return \Chill\MainBundle\Pagination\Page - * @throws \RuntimeException if the next page does not exists */ public function getNextPage() { if (!$this->hasNextPage()) { - throw new \RuntimeException("this page has no next page"); + throw new RuntimeException('this page has no next page'); } - + return $this->getPage($this->currentPageNumber + 1); } /** + * @param type $number + * + * @return \Chill\MainBundle\Pagination\Page + */ + public function getPage($number) + { + if (!$this->hasPage($number)) { + throw new RuntimeException("The page with number {$number} does not " + . 'exists'); + } + + return new Page( + $number, + $this->itemPerPage, + $this->urlGenerator, + $this->route, + array_merge($this->routeParameters, [ + $this->pageKey => $number, + $this->itemPerPageKey => $this->itemPerPage, + ]), + $this->totalItems + ); + } + + public function getPagesGenerator() + { + for ($i = 1; $this->countPages() >= $i; ++$i) { + yield $this->getPage($i); + } + } + + /** + * @throws RuntimeException if the next page does not exists * * @return \Chill\MainBundle\Pagination\Page - * @throws \RuntimeException if the next page does not exists */ public function getPreviousPage() { if (!$this->hasPreviousPage()) { - throw new \RuntimeException("this page has no previous page"); + throw new RuntimeException('this page has no previous page'); } - + return $this->getPage($this->currentPageNumber - 1); } + public function getTotalItems() + { + return $this->totalItems; + } + /** - * * @return bool */ public function hasNextPage() @@ -197,51 +203,27 @@ class Paginator implements PaginatorInterface return $this->hasPage($this->currentPageNumber + 1); } + public function hasPage($number) + { + return 0 < $number + and $this->countPages() >= $number; + } + /** - * * @return bool */ public function hasPreviousPage() { return $this->hasPage($this->currentPageNumber - 1); } - - public function hasPage($number) + + public function isCurrentPage(PageInterface $page) { - return $number > 0 and - $number <= $this->countPages(); + return $page->getNumber() === $this->currentPageNumber; } - - /** - * - * @param type $number - * @return \Chill\MainBundle\Pagination\Page - */ - public function getPage($number) { - if (!$this->hasPage($number)) { - throw new \RuntimeException("The page with number $number does not " - . "exists"); - } - - return new Page( - $number, - $this->itemPerPage, - $this->urlGenerator, - $this->route, - array_merge($this->routeParameters, array( - $this->pageKey => $number, - $this->itemPerPageKey => $this->itemPerPage - )), - $this->totalItems - ); - } - - public function getPagesGenerator() + public function setItemsPerPage($itemPerPage) { - for ($i = 1; $i <= $this->countPages(); $i++) { - yield $this->getPage($i); - } + $this->itemPerPage = $itemPerPage; } - } diff --git a/src/Bundle/ChillMainBundle/Pagination/PaginatorFactory.php b/src/Bundle/ChillMainBundle/Pagination/PaginatorFactory.php index 0e8338da3..85d161fc6 100644 --- a/src/Bundle/ChillMainBundle/Pagination/PaginatorFactory.php +++ b/src/Bundle/ChillMainBundle/Pagination/PaginatorFactory.php @@ -1,36 +1,28 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; -use Symfony\Component\Routing\RouterInterface; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\RouterInterface; /** - * Create paginator instances - * - * @author Julien Fastré - * @author Champs Libres + * Create paginator instances. */ class PaginatorFactory { + public const DEFAULT_CURRENT_PAGE_KEY = 'page'; + + public const DEFAULT_ITEM_PER_NUMBER_KEY = 'item_per_page'; + + public const DEFAULT_PAGE_NUMBER = 1; + /** * the default item per page. This may be overriden by * the request or inside the paginator. @@ -38,38 +30,33 @@ class PaginatorFactory * @var int */ private $itemPerPage; - + /** - * the router and generator for url - * - * @var RouterInterface - */ - private $router; - - /** - * the request stack + * the request stack. * * @var RequestStack */ private $requestStack; - - const DEFAULT_CURRENT_PAGE_KEY = 'page'; - const DEFAULT_ITEM_PER_NUMBER_KEY = 'item_per_page'; - const DEFAULT_PAGE_NUMBER = 1; - - + + /** + * the router and generator for url. + * + * @var RouterInterface + */ + private $router; + public function __construct( - RequestStack $requestStack, - RouterInterface $router, - $itemPerPage = 50 + RequestStack $requestStack, + RouterInterface $router, + $itemPerPage = 50 ) { $this->itemPerPage = $itemPerPage; $this->requestStack = $requestStack; $this->router = $router; } - + /** - * create a paginator instance + * create a paginator instance. * * The default route and route parameters are the current ones. If set, * thos route are overriden. @@ -77,70 +64,70 @@ class PaginatorFactory * @param int $totalItems * @param string|null $route the specific route to use in pages * @param array|null $routeParameters the specific route parameters to use in pages + * * @return PaginatorInterface */ public function create( - $totalItems, - $route = null, - array $routeParameters = null + $totalItems, + $route = null, + ?array $routeParameters = null ) { - return new Paginator( - $totalItems, - $this->getCurrentItemsPerPage(), - $this->getCurrentPageNumber(), - $route === null ? $this->getCurrentRoute() : $route, - $routeParameters === null ? $this->getCurrentRouteParameters() : + $totalItems, + $this->getCurrentItemsPerPage(), + $this->getCurrentPageNumber(), + null === $route ? $this->getCurrentRoute() : $route, + null === $routeParameters ? $this->getCurrentRouteParameters() : $routeParameters, - $this->router, - self::DEFAULT_CURRENT_PAGE_KEY, - self::DEFAULT_ITEM_PER_NUMBER_KEY); + $this->router, + self::DEFAULT_CURRENT_PAGE_KEY, + self::DEFAULT_ITEM_PER_NUMBER_KEY + ); } - - /** - * - * @return int - */ - public function getCurrentPageNumber() - { - return $this->requestStack - ->getCurrentRequest() - ->query - ->getInt(self::DEFAULT_CURRENT_PAGE_KEY, self::DEFAULT_PAGE_NUMBER); - } - + public function getCurrentItemsPerPage() { return $this->requestStack - ->getCurrentRequest() - ->query - ->getInt(self::DEFAULT_ITEM_PER_NUMBER_KEY, $this->itemPerPage); + ->getCurrentRequest() + ->query + ->getInt(self::DEFAULT_ITEM_PER_NUMBER_KEY, $this->itemPerPage); } - + public function getCurrentPageFirstItemNumber() { return ($this->getCurrentPageNumber() - 1) * $this->getCurrentItemsPerPage(); } - + + /** + * @return int + */ + public function getCurrentPageNumber() + { + return $this->requestStack + ->getCurrentRequest() + ->query + ->getInt(self::DEFAULT_CURRENT_PAGE_KEY, self::DEFAULT_PAGE_NUMBER); + } + protected function getCurrentRoute() { $request = $this->requestStack->getCurrentRequest(); - + return $request->get('_route'); } - + protected function getCurrentRouteParameters() { return array_merge( - $this->router->getContext()->getParameters(), - // get the route parameters + $this->router->getContext()->getParameters(), + // get the route parameters $this->requestStack - ->getCurrentRequest() - ->attributes->get('_route_params'), - // get the query parameters + ->getCurrentRequest() + ->attributes->get('_route_params'), + // get the query parameters $this->requestStack - ->getCurrentRequest()->query->all() - ); + ->getCurrentRequest()->query->all() + ); } } diff --git a/src/Bundle/ChillMainBundle/Pagination/PaginatorInterface.php b/src/Bundle/ChillMainBundle/Pagination/PaginatorInterface.php index b9ee9c8a6..010831a62 100644 --- a/src/Bundle/ChillMainBundle/Pagination/PaginatorInterface.php +++ b/src/Bundle/ChillMainBundle/Pagination/PaginatorInterface.php @@ -1,27 +1,20 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Pagination; +use Countable; +use Generator; +use RuntimeException; + /** - * Represent a set of numbered pages + * Represent a set of numbered pages. * * Allow to calculate and render pagination for a set of pages. * @@ -29,108 +22,108 @@ namespace Chill\MainBundle\Pagination; * into pages. Each page is numbered and count a given number of item per page. * * The first page number is 1, although the first result number is 0. - * - * @author Julien Fastré */ -interface PaginatorInterface extends \Countable +interface PaginatorInterface extends Countable { - /** - * get the number of results for this paginator - * - * @return int - */ - public function getTotalItems(); - - /** - * get the first result for the current page - * - * @return int - */ - public function getCurrentPageFirstItemNumber(); - - /* - * get the number of items per page - */ - public function getItemsPerPage(); - - /* - * set the number of items per page - */ - public function setItemsPerPage($itemsPerPage); - /** * get the number of pages for this pagination. * * @return int */ public function countPages(); - + /** - * get the current page + * get the current page. * * @return PageInterface */ public function getCurrentPage(); - + /** - * check if the given page is the current page + * get the first result for the current page. * - * @param \Chill\MainBundle\Pagination\PageInterface $page - * @return bool + * @return int */ - public function isCurrentPage(PageInterface $page); - + public function getCurrentPageFirstItemNumber(); + + /* + * get the number of items per page + */ + public function getItemsPerPage(); + /** - * check if the page with the given number exists + * get the next page. * - * @param int $number - */ - public function hasPage($number); - - /** - * get page by his number - * - * @param int $number - * @throws \RuntimeException if the pagination has no page with specified number - */ - public function getPage($number); - - /** - * get the next page + * @throws RuntimeException if the pagination has not next page * * @return PageInterface - * @throws \RuntimeException if the pagination has not next page */ public function getNextPage(); - + /** - * get the previous page + * get page by his number. + * + * @param int $number + * + * @throws RuntimeException if the pagination has no page with specified number + */ + public function getPage($number); + + /** + * get a generator to generate pages. + * + * @return Generator which return PageInterface elements + */ + public function getPagesGenerator(); + + /** + * get the previous page. + * + * @throws RuntimeException if the pagination has not previous page * * @return PageInterface - * @throws \RuntimeException if the pagination has not previous page */ public function getPreviousPage(); - + /** - * check if the current page has a next page + * get the number of results for this paginator. + * + * @return int + */ + public function getTotalItems(); + + /** + * check if the current page has a next page. * * @return bool */ public function hasNextPage(); - + /** - * check if the current page has a page before + * check if the page with the given number exists. + * + * @param int $number + */ + public function hasPage($number); + + /** + * check if the current page has a page before. * * @return bool */ public function hasPreviousPage(); - + /** - * get a generator to generate pages + * check if the given page is the current page. * - * @return \Generator which return PageInterface elements + * @param \Chill\MainBundle\Pagination\PageInterface $page + * + * @return bool */ - public function getPagesGenerator(); - - + public function isCurrentPage(PageInterface $page); + + /* + * set the number of items per page + */ + public function setItemsPerPage($itemsPerPage); } diff --git a/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php b/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php index c2ab59442..210fc07de 100644 --- a/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php +++ b/src/Bundle/ChillMainBundle/Phonenumber/PhonenumberHelper.php @@ -1,28 +1,25 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Phonenumber; use GuzzleHttp\Client; use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Exception\ConnectException; -use Psr\Log\LoggerInterface; +use GuzzleHttp\Exception\ServerException; use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; + +use function array_key_exists; +use function in_array; +use function json_decode; +use function preg_replace; /** * Helper to some task linked to phonenumber. @@ -30,27 +27,26 @@ use Psr\Cache\CacheItemPoolInterface; * Currently, only Twilio is supported (https://www.twilio.com/lookup). A method * allow to check if the helper is configured for validation. This should be used * before doing some validation. - * - * */ class PhonenumberHelper { + public const FORMAT_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s'; + + public const LOOKUP_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s'; + + protected CacheItemPoolInterface $cachePool; + /** - * Twilio client - */ - protected Client $twilioClient; - - /** - * TRUE if the client is properly configured + * TRUE if the client is properly configured. */ protected bool $isConfigured = false; protected LoggerInterface $logger; - protected CacheItemPoolInterface $cachePool; - - const LOOKUP_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s'; - const FORMAT_URI = 'https://lookups.twilio.com/v1/PhoneNumbers/%s'; + /** + * Twilio client. + */ + protected Client $twilioClient; public function __construct( CacheItemPoolInterface $cachePool, @@ -60,107 +56,19 @@ class PhonenumberHelper $this->logger = $logger; $this->cachePool = $cachePool; - if (\array_key_exists('twilio_sid', $config) + if ( + array_key_exists('twilio_sid', $config) && !empty($config['twilio_sid']) && strlen($config['twilio_sid']) > 2 - && \array_key_exists('twilio_secret', $config) + && array_key_exists('twilio_secret', $config) && !empty($config['twilio_secret']) && strlen($config['twilio_secret']) > 2 - ) { - + ) { $this->twilioClient = new Client([ - 'auth' => [ $config['twilio_sid'], $config['twilio_secret'] ] + 'auth' => [$config['twilio_sid'], $config['twilio_secret']], ]); - $this->isConfigured = TRUE; + $this->isConfigured = true; } - - } - - /** - * Return true if the validation is configured and available. - * - * @return bool - */ - public function isPhonenumberValidationConfigured() : bool - { - return $this->isConfigured; - } - - /** - * REturn true if the phoennumber is a mobile phone. Return always true - * if the validation is not configured. - * - * @param string $phonenumber - * @return bool - */ - public function isValidPhonenumberMobile($phonenumber) : bool - { - if (FALSE === $this->isPhonenumberValidationConfigured()) { - return true; - } - - $validation = $this->performTwilioLookup($phonenumber); - - if (NULL === $validation) { - return true; - } - - return $validation === 'mobile'; - } - - /** - * Return true if the phonenumber is a landline or voip phone. Return always true - * if the validation is not configured. - * - * @param string $phonenumber - * @return bool - */ - public function isValidPhonenumberLandOrVoip($phonenumber) : bool - { - if (FALSE === $this->isPhonenumberValidationConfigured()) { - return true; - } - - $validation = $this->performTwilioLookup($phonenumber); - - if (NULL === $validation) { - return true; - } - - return \in_array($validation, [ 'landline', 'voip' ]); - } - - /** - * Return true if the phonenumber is a landline or voip phone. Return always true - * if the validation is not configured. - * - * @param string $phonenumber - * @return bool - */ - public function isValidPhonenumberAny($phonenumber) : bool - { - if (FALSE === $this->isPhonenumberValidationConfigured()) { - return true; - } - $validation = $this->performTwilioLookup($phonenumber); -; - if (NULL === $validation) { - return false; - } - - return \in_array($validation, [ 'landline', 'voip', 'mobile' ]); - } - - /** - * Get type (mobile, landline, ...) for phone number - * - * @param string $phonenumber - * - * @return string - */ - public function getType(string $phonenumber): string - { - return $this->performTwilioLookup($phonenumber) ?? 'unknown'; } public function format($phonenumber) @@ -168,63 +76,139 @@ class PhonenumberHelper return $this->performTwilioFormat($phonenumber); } + /** + * Get type (mobile, landline, ...) for phone number. + */ + public function getType(string $phonenumber): string + { + return $this->performTwilioLookup($phonenumber) ?? 'unknown'; + } + + /** + * Return true if the validation is configured and available. + */ + public function isPhonenumberValidationConfigured(): bool + { + return $this->isConfigured; + } + + /** + * Return true if the phonenumber is a landline or voip phone. Return always true + * if the validation is not configured. + * + * @param string $phonenumber + */ + public function isValidPhonenumberAny($phonenumber): bool + { + if (false === $this->isPhonenumberValidationConfigured()) { + return true; + } + $validation = $this->performTwilioLookup($phonenumber); + + if (null === $validation) { + return false; + } + + return in_array($validation, ['landline', 'voip', 'mobile']); + } + + /** + * Return true if the phonenumber is a landline or voip phone. Return always true + * if the validation is not configured. + * + * @param string $phonenumber + */ + public function isValidPhonenumberLandOrVoip($phonenumber): bool + { + if (false === $this->isPhonenumberValidationConfigured()) { + return true; + } + + $validation = $this->performTwilioLookup($phonenumber); + + if (null === $validation) { + return true; + } + + return in_array($validation, ['landline', 'voip']); + } + + /** + * REturn true if the phoennumber is a mobile phone. Return always true + * if the validation is not configured. + * + * @param string $phonenumber + */ + public function isValidPhonenumberMobile($phonenumber): bool + { + if (false === $this->isPhonenumberValidationConfigured()) { + return true; + } + + $validation = $this->performTwilioLookup($phonenumber); + + if (null === $validation) { + return true; + } + + return 'mobile' === $validation; + } + protected function performTwilioFormat($phonenumber) { - if (FALSE === $this->isPhonenumberValidationConfigured()) { + if (false === $this->isPhonenumberValidationConfigured()) { return $phonenumber; } // filter only number - $filtered = \preg_replace("/[^0-9]/", "", $phonenumber); + $filtered = preg_replace('/[^0-9]/', '', $phonenumber); - $item = $this->cachePool->getItem('pnum_format_nat_'.$filtered); + $item = $this->cachePool->getItem('pnum_format_nat_' . $filtered); if ($item->isHit()) { return $item->get(); } try { - $response = $this->twilioClient->get(sprintf(self::FORMAT_URI, '+'.$filtered), [ + $response = $this->twilioClient->get(sprintf(self::FORMAT_URI, '+' . $filtered), [ 'http_errors' => true, ]); - - } catch (ClientException $e) { + } catch (ClientException $e) { $response = $e->getResponse(); - $this->logger->error("[phonenumber helper] Could not format number " - . "due to client error", [ - "message" => $response->getBody()->getContents(), - "status_code" => $response->getStatusCode(), - "phonenumber" => $phonenumber - ]); + $this->logger->error('[phonenumber helper] Could not format number ' + . 'due to client error', [ + 'message' => $response->getBody()->getContents(), + 'status_code' => $response->getStatusCode(), + 'phonenumber' => $phonenumber, + ]); return $phonenumber; } catch (ServerException $e) { $response = $e->getResponse(); - $this->logger->error("[phonenumber helper] Could not format number " - . "due to server error", [ - "message" => $response->getBody()->getContents(), - "status_code" => $response->getStatusCode(), - "phonenumber" => $phonenumber - ]); + $this->logger->error('[phonenumber helper] Could not format number ' + . 'due to server error', [ + 'message' => $response->getBody()->getContents(), + 'status_code' => $response->getStatusCode(), + 'phonenumber' => $phonenumber, + ]); return null; } catch (ConnectException $e) { - $this->logger->error("[phonenumber helper] Could not format number " - . "due to connect error", [ - "message" => $e->getMessage(), - "phonenumber" => $phonenumber - ]); + $this->logger->error('[phonenumber helper] Could not format number ' + . 'due to connect error', [ + 'message' => $e->getMessage(), + 'phonenumber' => $phonenumber, + ]); return null; } - $format = \json_decode($response->getBody())->national_format; + $format = json_decode($response->getBody())->national_format; $item ->set($format) // expires after 3d - ->expiresAfter(3600 * 24 * 3) - ; + ->expiresAfter(3600 * 24 * 3); $this->cachePool->save($item); @@ -233,55 +217,54 @@ class PhonenumberHelper protected function performTwilioLookup($phonenumber) { - if (FALSE === $this->isPhonenumberValidationConfigured()) { + if (false === $this->isPhonenumberValidationConfigured()) { return null; } // filter only number - $filtered = \preg_replace("/[^0-9]/", "", $phonenumber); + $filtered = preg_replace('/[^0-9]/', '', $phonenumber); - $item = $this->cachePool->getItem('pnum_'.$filtered); + $item = $this->cachePool->getItem('pnum_' . $filtered); if ($item->isHit()) { //return $item->get(); } try { - $response = $this->twilioClient->get(sprintf(self::LOOKUP_URI, '+'.$filtered), [ + $response = $this->twilioClient->get(sprintf(self::LOOKUP_URI, '+' . $filtered), [ 'http_errors' => true, 'query' => [ - 'Type' => 'carrier' - ] + 'Type' => 'carrier', + ], ]); - } catch (ClientException $e) { + } catch (ClientException $e) { return 'invalid'; } catch (ServerException $e) { $response = $e->getResponse(); - $this->logger->error("[phonenumber helper] Could not perform validation " - . "due to server error", [ - "message" => $response->getBody()->getContents(), - "status_code" => $response->getStatusCode(), - "phonenumber" => $phonenumber - ]); + $this->logger->error('[phonenumber helper] Could not perform validation ' + . 'due to server error', [ + 'message' => $response->getBody()->getContents(), + 'status_code' => $response->getStatusCode(), + 'phonenumber' => $phonenumber, + ]); return null; } catch (ConnectException $e) { - $this->logger->error("[phonenumber helper] Could not format number " - . "due to connect error", [ - "message" => $e->getMessage(), - "phonenumber" => $phonenumber - ]); + $this->logger->error('[phonenumber helper] Could not format number ' + . 'due to connect error', [ + 'message' => $e->getMessage(), + 'phonenumber' => $phonenumber, + ]); return null; } - $validation = \json_decode($response->getBody())->carrier->type; + $validation = json_decode($response->getBody())->carrier->type; $item ->set($validation) // expires after 12h - ->expiresAfter(3600 * 12) - ; + ->expiresAfter(3600 * 12); $this->cachePool->save($item); diff --git a/src/Bundle/ChillMainBundle/Phonenumber/Templating.php b/src/Bundle/ChillMainBundle/Phonenumber/Templating.php index 45bfceae0..b21ca50db 100644 --- a/src/Bundle/ChillMainBundle/Phonenumber/Templating.php +++ b/src/Bundle/ChillMainBundle/Phonenumber/Templating.php @@ -1,52 +1,38 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Phonenumber; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; -use Chill\MainBundle\Phonenumber\PhonenumberHelper; -/** - * - * - */ class Templating extends AbstractExtension { /** - * * @var PhonenumberHelper */ protected $phonenumberHelper; - + public function __construct(PhonenumberHelper $phonenumberHelper) { $this->phonenumberHelper = $phonenumberHelper; } - public function getFilters() - { - return [ - new TwigFilter('chill_format_phonenumber', [$this, 'formatPhonenumber']) - ]; - } - public function formatPhonenumber($phonenumber) { return $this->phonenumberHelper->format($phonenumber) ?? $phonenumber; } + + public function getFilters() + { + return [ + new TwigFilter('chill_format_phonenumber', [$this, 'formatPhonenumber']), + ]; + } } diff --git a/src/Bundle/ChillMainBundle/Redis/ChillRedis.php b/src/Bundle/ChillMainBundle/Redis/ChillRedis.php index a196d2b60..ce8a829ad 100644 --- a/src/Bundle/ChillMainBundle/Redis/ChillRedis.php +++ b/src/Bundle/ChillMainBundle/Redis/ChillRedis.php @@ -1,26 +1,19 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Redis; /** - * Redis client configured by chill main + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ -class ChillRedis extends \Redis + +namespace Chill\MainBundle\Redis; + +use Redis; + +/** + * Redis client configured by chill main. + */ +class ChillRedis extends Redis { } diff --git a/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php b/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php index 89d877405..bcbc50c03 100644 --- a/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php +++ b/src/Bundle/ChillMainBundle/Redis/RedisConnectionFactory.php @@ -1,29 +1,17 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Redis; - -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Redis; + +use RuntimeException; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + class RedisConnectionFactory implements EventSubscriberInterface { protected string $host; @@ -31,7 +19,6 @@ class RedisConnectionFactory implements EventSubscriberInterface protected int $port; /** - * * @var Redis */ protected ChillRedis $redis; @@ -44,35 +31,33 @@ class RedisConnectionFactory implements EventSubscriberInterface $this->port = (int) $parameters['port']; $this->timeout = (int) $parameters['timeout']; } - - + + public function create() + { + $redis = $this->redis = new ChillRedis(); + + $result = $redis->connect($this->host, $this->port, $this->timeout); + + if (false === $result) { + throw new RuntimeException('Could not connect to redis instance'); + } + + return $redis; + } + public static function getSubscribedEvents(): array { return [ 'kernel.finish_request' => [ - [ 'onKernelFinishRequest' ] - ] + ['onKernelFinishRequest'], + ], ]; } - - public function create() - { - $redis = $this->redis = new ChillRedis(); - - $result = $redis->connect($this->host, $this->port, $this->timeout); - - if (FALSE === $result) { - throw new \RuntimeException("Could not connect to redis instance"); - } - - return $redis; - } - + public function onKernelFinishRequest() { - if ($this->redis !== null) { + if (null !== $this->redis) { $this->redis->close(); } } - } diff --git a/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php b/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php index 208151420..273d68628 100644 --- a/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/AddressReferenceRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?AddressReference @@ -46,5 +53,5 @@ class AddressReferenceRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php index 05a439bfd..ded666422 100644 --- a/src/Bundle/ChillMainBundle/Repository/CenterRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/CenterRepository.php @@ -1,27 +1,14 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Repository; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Repository; + class CenterRepository extends \Doctrine\ORM\EntityRepository { - } diff --git a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php index 5b8ab8423..5034c9fc5 100644 --- a/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/PostalCodeRepository.php @@ -1,28 +1,14 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Repository; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Repository; + class PostalCodeRepository extends \Doctrine\ORM\EntityRepository { - } diff --git a/src/Bundle/ChillMainBundle/Repository/UserRepository.php b/src/Bundle/ChillMainBundle/Repository/UserRepository.php index 51bcda6eb..408d052d2 100644 --- a/src/Bundle/ChillMainBundle/Repository/UserRepository.php +++ b/src/Bundle/ChillMainBundle/Repository/UserRepository.php @@ -1,121 +1,107 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Repository; use Chill\MainBundle\Entity\GroupCenter; use Chill\MainBundle\Entity\User; -/** - * - * - */ class UserRepository extends \Doctrine\ORM\EntityRepository { public function countByUsernameOrEmail($pattern) { $qb = $this->queryByUsernameOrEmail($pattern); - + $qb->select('COUNT(u)'); - + return (int) $qb->getQuery()->getSingleScalarResult(); } - - public function findByUsernameOrEmail($pattern) + + public function findByUsernameOrEmail($pattern) { $qb = $this->queryByUsernameOrEmail($pattern); - + return $qb->getQuery()->getResult(); } - + public function findOneByUsernameOrEmail($pattern) { $qb = $this->queryByUsernameOrEmail($pattern); - + return $qb->getQuery()->getSingleResult(); } - + /** - * Get the users having a specific flags - * - * If provided, only the users amongst "filtered users" are searched. This - * allows to make a first search amongst users based on role and center + * Get the users having a specific flags. + * + * If provided, only the users amongst "filtered users" are searched. This + * allows to make a first search amongst users based on role and center * and, then filter those users having some flags. - * + * * @param \Chill\MainBundle\Entity\User[] $amongstUsers + * @param mixed $flag */ public function findUsersHavingFlags($flag, $amongstUsers = []) { - $gcs = $this->_em->createQuery("SELECT DISTINCT gc " - . "FROM ".GroupCenter::class." gc " - . "JOIN gc.permissionsGroup pg " - . "WHERE " - . "JSONB_EXISTS_IN_ARRAY(pg.flags, :flag) = :true ") + $gcs = $this->_em->createQuery('SELECT DISTINCT gc ' + . 'FROM ' . GroupCenter::class . ' gc ' + . 'JOIN gc.permissionsGroup pg ' + . 'WHERE ' + . 'JSONB_EXISTS_IN_ARRAY(pg.flags, :flag) = :true ') ->setParameters([ 'true' => true, - 'flag' => $flag + 'flag' => $flag, ]) ->getResult(); - + if (count($gcs) === 0) { return []; } - + $qb = $this->_em->createQueryBuilder(); $qb ->select('DISTINCT u') ->from(User::class, 'u') - ->where("u.enabled = 'TRUE'") - ; - + ->where("u.enabled = 'TRUE'"); + $orx = $qb->expr()->orX(); - foreach($gcs as $i => $gc) { - $orx->add(':gc_'.$i.' MEMBER OF u.groupCenters'); - $qb->setParameter('gc_'.$i, $gc); + + foreach ($gcs as $i => $gc) { + $orx->add(':gc_' . $i . ' MEMBER OF u.groupCenters'); + $qb->setParameter('gc_' . $i, $gc); } - + $qb->andWhere($orx); - + if (count($amongstUsers) > 0) { $qb ->andWhere($qb->expr()->in('u', ':amongstUsers')) - ->setParameter('amongstUsers', $amongstUsers) - ; + ->setParameter('amongstUsers', $amongstUsers); } - + return $qb->getQuery()->getResult(); } - + protected function queryByUsernameOrEmail($pattern) { $qb = $this->createQueryBuilder('u'); - + $searchByPattern = $qb->expr()->orX(); - + $searchByPattern ->add($qb->expr()->eq('u.usernameCanonical', 'LOWER(UNACCENT(:pattern))')) - ->add($qb->expr()->eq('u.emailCanonical', 'LOWER(UNACCENT(:pattern))')) - ; - + ->add($qb->expr()->eq('u.emailCanonical', 'LOWER(UNACCENT(:pattern))')); + $qb ->where($searchByPattern) - ->setParameter('pattern', $pattern) - ; - + ->setParameter('pattern', $pattern); + return $qb; } } diff --git a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php index 10886518a..1e2499c40 100644 --- a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php +++ b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/AppKernel.php @@ -1,13 +1,36 @@ -load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - } - - /** - * @return string - */ - public function getCacheDir() - { - return sys_get_temp_dir().'/ChillMainBundle/cache'; - } - - /** - * @return string - */ - public function getLogDir() - { - return sys_get_temp_dir().'/ChillMainBundle/logs'; - } + { + $loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml'); + } } diff --git a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/autoload.php b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/autoload.php index 39dc0e2ba..a2dfe7f92 100644 --- a/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/autoload.php +++ b/src/Bundle/ChillMainBundle/Resources/test/Fixtures/App/app/autoload.php @@ -1,11 +1,18 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Routing\Loader; @@ -24,56 +13,47 @@ use Symfony\Component\Config\Loader\Loader; use Symfony\Component\Routing\RouteCollection; /** - * Import routes from bundles - * - * Routes must be defined in configuration, add an entry - * under `chill_main.routing.resources` - * - * + * Import routes from bundles. * - * @author Julien Fastré + * Routes must be defined in configuration, add an entry + * under `chill_main.routing.resources` */ class ChillRoutesLoader extends Loader { private $routes; - - - + public function __construct(array $routes) { $this->routes = $routes; } - + /** - * {@inheritDoc} - * * @param type $resource * @param type $type + * * @return RouteCollection */ public function load($resource, $type = null) { $collection = new RouteCollection(); - + foreach ($this->routes as $resource) { $collection->addCollection( - $this->import($resource, NULL) - ); + $this->import($resource, null) + ); } - + return $collection; } /** - * {@inheritDoc} - * * @param type $resource * @param type $type - * @return boolean + * + * @return bool */ public function supports($resource, $type = null) { return 'chill_routes' === $type; } - } diff --git a/src/Bundle/ChillMainBundle/Routing/LocalMenuBuilderInterface.php b/src/Bundle/ChillMainBundle/Routing/LocalMenuBuilderInterface.php index 37f7ead40..c26b13586 100644 --- a/src/Bundle/ChillMainBundle/Routing/LocalMenuBuilderInterface.php +++ b/src/Bundle/ChillMainBundle/Routing/LocalMenuBuilderInterface.php @@ -1,38 +1,26 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Routing; use Knp\Menu\MenuItem; -/** - * - * @author Julien Fastré - */ interface LocalMenuBuilderInterface { + public function buildMenu($menuId, MenuItem $menu, array $parameters); + /** - * return an array of menu ids - * - * @internal this method is static to 1. keep all config in the class, + * return an array of menu ids. + * + * @internal this method is static to 1. keep all config in the class, * instead of tags arguments; 2. avoid a "supports" method, which could lead * to parsing all instances to get only one or two working instance. */ public static function getMenuIds(): array; - - public function buildMenu($menuId, MenuItem $menu, array $parameters); } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php index 96a63ff75..0188cf97d 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/AdminSectionMenuBuilder.php @@ -1,62 +1,48 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Routing\MenuBuilder; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\MainBundle\Security\Authorization\ChillExportVoter; -/** - * - * - */ class AdminSectionMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + public function __construct(AuthorizationCheckerInterface $authorizationChecker) { $this->authorizationChecker = $authorizationChecker; } - + public function buildMenu($menuId, MenuItem $menu, array $parameters) { // all the entries below must have ROLE_ADMIN permissions if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) { return; } - + $menu->addChild('Users and permissions', [ - 'route' => 'chill_main_admin_permissions' - ]) + 'route' => 'chill_main_admin_permissions', + ]) ->setExtras([ 'icons' => ['key'], - 'order' => 200 + 'order' => 200, ]); } public static function getMenuIds(): array { - return [ 'admin_section' ]; + return ['admin_section']; } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php index b52a0502e..d53878be0 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/SectionMenuBuilder.php @@ -1,35 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Routing\MenuBuilder; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\MainBundle\Security\Authorization\ChillExportVoter; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\MainBundle\Security\Authorization\ChillExportVoter; use Symfony\Component\Translation\TranslatorInterface; /** - * Class SectionMenuBuilder - * - * @package Chill\MainBundle\Routing\MenuBuilder - * @author Julien Fastré + * Class SectionMenuBuilder. */ class SectionMenuBuilder implements LocalMenuBuilderInterface { @@ -37,54 +24,47 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + /** * @var TranslatorInterface */ protected $translator; - + /** * SectionMenuBuilder constructor. - * - * @param AuthorizationCheckerInterface $authorizationChecker */ public function __construct(AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator) { $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; } - + /** * @param $menuId - * @param MenuItem $menu - * @param array $parameters */ public function buildMenu($menuId, MenuItem $menu, array $parameters) { $menu->addChild($this->translator->trans('Homepage'), [ - 'route' => 'chill_main_homepage' - ]) + 'route' => 'chill_main_homepage', + ]) ->setExtras([ 'icons' => ['home'], - 'order' => 0 + 'order' => 0, ]); - + if ($this->authorizationChecker->isGranted(ChillExportVoter::EXPORT)) { $menu->addChild($this->translator->trans('Export Menu'), [ - 'route' => 'chill_main_export_index' + 'route' => 'chill_main_export_index', ]) - ->setExtras([ - 'icons' => ['upload'], - 'order' => 20 - ]); + ->setExtras([ + 'icons' => ['upload'], + 'order' => 20, + ]); } } - - /** - * @return array - */ + public static function getMenuIds(): array { - return [ 'section' ]; + return ['section']; } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php index 010f5609d..8dd0069da 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php @@ -1,71 +1,58 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Routing\MenuBuilder; - -use Chill\MainBundle\Routing\LocalMenuBuilderInterface; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Routing\MenuBuilder; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; + class UserMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var TokenStorageInterface */ protected $tokenStorage; - + public function __construct(TokenStorageInterface $tokenStorage) { $this->tokenStorage = $tokenStorage; } - + public function buildMenu($menuId, \Knp\Menu\MenuItem $menu, array $parameters) { if ($this->tokenStorage->getToken()->getUser() instanceof User) { $menu ->addChild( 'Change password', - [ 'route' => 'change_my_password'] + ['route' => 'change_my_password'] ) ->setExtras([ - 'order' => 99999999998 + 'order' => 99999999998, ]); } - + $menu ->addChild( - 'Logout', + 'Logout', [ - 'route' => 'logout' - ]) + 'route' => 'logout', + ] + ) ->setExtras([ - 'order'=> 99999999999, - 'icon' => 'power-off' + 'order' => 99999999999, + 'icon' => 'power-off', ]); } public static function getMenuIds(): array { - return [ 'user' ]; + return ['user']; } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuComposer.php b/src/Bundle/ChillMainBundle/Routing/MenuComposer.php index 0bcee4c81..1dccb684f 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuComposer.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuComposer.php @@ -1,51 +1,52 @@ translator = $translator; } - /** - * Set the route Collection - * This function is needed for testing purpose: routeCollection is not - * available as a service (RouterInterface is provided as a service and - * added to this class as paramater in __construct) - * - * @param RouteCollection $routeCollection - */ - public function setRouteCollection(RouteCollection $routeCollection) + public function addLocalMenuBuilder(LocalMenuBuilderInterface $menuBuilder, $menuId) { - $this->routeCollection = $routeCollection; + $this->localMenuBuilders[$menuId][] = $menuBuilder; + } + + public function getMenuFor($menuId, array $parameters = []) + { + $routes = $this->getRoutesFor($menuId, $parameters); + $menu = $this->menuFactory->createItem($menuId); + + // build menu from routes + foreach ($routes as $order => $route) { + $menu->addChild($this->translator->trans($route['label']), [ + 'route' => $route['key'], + 'routeParameters' => $parameters['args'], + 'order' => $order, + ]) + ->setExtras([ + //'icon' => $route['icon'], + // sf4 check: commented to avoid error: `An exception has been thrown during the rendering of a template ("Notice: Undefined index: icon").` + 'order' => $order, + ]); + } + + if ($this->hasLocalMenuBuilder($menuId)) { + foreach ($this->localMenuBuilders[$menuId] as $builder) { + /* @var $builder LocalMenuBuilderInterface */ + $builder->buildMenu($menuId, $menu, $parameters['args']); + } + } + + $this->reorderMenu($menu); + + return $menu; } /** * Return an array of routes added to $menuId, - * The array is aimed to build route with MenuTwig - * + * The array is aimed to build route with MenuTwig. + * * @param string $menuId * @param array $parameters see https://redmine.champs-libres.coop/issues/179 + * * @return array */ - public function getRoutesFor($menuId, array $parameters = array()) + public function getRoutesFor($menuId, array $parameters = []) { - $routes = array(); + $routes = []; $routeCollection = $this->router->getRouteCollection(); foreach ($routeCollection->all() as $routeKey => $route) { if ($route->hasOption('menus')) { - if (array_key_exists($menuId, $route->getOption('menus'))) { $route = $route->getOption('menus')[$menuId]; @@ -101,97 +125,69 @@ class MenuComposer return $routes; } - - public function getMenuFor($menuId, array $parameters = array()) - { - $routes = $this->getRoutesFor($menuId, $parameters); - $menu = $this->menuFactory->createItem($menuId); - - // build menu from routes - foreach ($routes as $order => $route) { - $menu->addChild($this->translator->trans($route['label']), [ - 'route' => $route['key'], - 'routeParameters' => $parameters['args'], - 'order' => $order - ]) - ->setExtras([ - //'icon' => $route['icon'], - // sf4 check: commented to avoid error: `An exception has been thrown during the rendering of a template ("Notice: Undefined index: icon").` - 'order' => $order - ]) - ; - } - - if ($this->hasLocalMenuBuilder($menuId)) { - foreach ($this->localMenuBuilders[$menuId] as $builder) { - /* @var $builder LocalMenuBuilderInterface */ - $builder->buildMenu($menuId, $menu, $parameters['args']); - } - } - - $this->reorderMenu($menu); - - return $menu; - } - - /** - * recursive function to resolve the order of a array of routes. - * If the order chosen in routing.yml is already in used, find the - * first next order available. - * - * @param array $routes the routes previously added - * @param int $order - * @return int - */ - private function resolveOrder($routes, $order) - { - if (isset($routes[$order])) { - return $this->resolveOrder($routes, $order + 1); - } else { - return $order; - } - } - - private function reorderMenu(ItemInterface $menu) - { - $ordered = []; - $unordered = []; - - foreach ($menu->getChildren() as $name => $item) { - $order = $item->getExtra('order'); - - if ($order !== null) { - $ordered[$this->resolveOrder($ordered, $order)] = $name; - } else { - $unordered = $name; - } - } - - ksort($ordered); - - $menus = \array_merge(\array_values($ordered), $unordered); - $menu->reorderChildren($menus); - } - - - public function addLocalMenuBuilder(LocalMenuBuilderInterface $menuBuilder, $menuId) - { - $this->localMenuBuilders[$menuId][] = $menuBuilder; - } - + /** * Return true if the menu has at least one builder. - * + * * This function is a helper to determine if the method `getMenuFor` * should be used, or `getRouteFor`. The method `getMenuFor` should be used * if the result is true (it **does** exists at least one menu builder. - * + * * @param string $menuId - * @return bool */ public function hasLocalMenuBuilder($menuId): bool { return \array_key_exists($menuId, $this->localMenuBuilders); } + /** + * Set the route Collection + * This function is needed for testing purpose: routeCollection is not + * available as a service (RouterInterface is provided as a service and + * added to this class as paramater in __construct). + */ + public function setRouteCollection(RouteCollection $routeCollection) + { + $this->routeCollection = $routeCollection; + } + + private function reorderMenu(ItemInterface $menu) + { + $ordered = []; + $unordered = []; + + foreach ($menu->getChildren() as $name => $item) { + $order = $item->getExtra('order'); + + if (null !== $order) { + $ordered[$this->resolveOrder($ordered, $order)] = $name; + } else { + $unordered = $name; + } + } + + ksort($ordered); + + $menus = array_merge(array_values($ordered), $unordered); + $menu->reorderChildren($menus); + } + + /** + * recursive function to resolve the order of a array of routes. + * If the order chosen in routing.yml is already in used, find the + * first next order available. + * + * @param array $routes the routes previously added + * @param int $order + * + * @return int + */ + private function resolveOrder($routes, $order) + { + if (isset($routes[$order])) { + return $this->resolveOrder($routes, $order + 1); + } + + return $order; + } } diff --git a/src/Bundle/ChillMainBundle/Routing/MenuTwig.php b/src/Bundle/ChillMainBundle/Routing/MenuTwig.php index fe233e205..536d5b555 100644 --- a/src/Bundle/ChillMainBundle/Routing/MenuTwig.php +++ b/src/Bundle/ChillMainBundle/Routing/MenuTwig.php @@ -1,27 +1,14 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Routing; -use Chill\MainBundle\Routing\MenuComposer; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Twig\Environment; @@ -29,90 +16,86 @@ use Twig\Extension\AbstractExtension; use Twig\TwigFunction; /** - * Add the filter 'chill_menu' - * - * @author Julien Fastré + * Add the filter 'chill_menu'. */ class MenuTwig extends AbstractExtension implements ContainerAwareInterface { - /** - * - * @var MenuComposer - */ - private $menuComposer; - - /** - * * @var \Symfony\Component\DependencyInjection\ContainerInterface */ private $container; - + /** - * the default parameters for chillMenu - * - * @var mixed[] + * the default parameters for chillMenu. + * + * @var mixed[] */ - private $defaultParams = array( + private $defaultParams = [ 'layout' => '@ChillMain/Menu/defaultMenu.html.twig', - 'args' => array(), - 'activeRouteKey' => null - ); - + 'args' => [], + 'activeRouteKey' => null, + ]; + + /** + * @var MenuComposer + */ + private $menuComposer; + public function __construct(MenuComposer $menuComposer) { $this->menuComposer = $menuComposer; } - - public function getFunctions() - { - return [new TwigFunction('chill_menu', - array($this, 'chillMenu'), array( - 'is_safe' => array('html'), - 'needs_environment' => true - )) - ]; - } - + /** - * Render a Menu corresponding to $menuId - * - * Expected params : + * Render a Menu corresponding to $menuId. + * + * Expected params : * - args: the arguments to build the path (i.e: if pattern is /something/{bar}, args must contain {'bar': 'foo'} * - layout: the layout. Absolute path needed (i.e.: ChillXyzBundle:section:foo.html.twig) * - activeRouteKey : the key active, will render the menu differently. - * + * * @deprecated link: see https://redmine.champs-libres.coop/issues/179 for more informations - * + * * @param string $menuId * @param mixed[] $params */ - public function chillMenu(Environment $env, $menuId, array $params = array()) + public function chillMenu(Environment $env, $menuId, array $params = []) { $resolvedParams = array_merge($this->defaultParams, $params); $layout = $resolvedParams['layout']; unset($resolvedParams['layout']); - + if ($this->menuComposer->hasLocalMenuBuilder($menuId) === false) { $resolvedParams['routes'] = $this->menuComposer->getRoutesFor($menuId, $resolvedParams); - - return $env->render($layout, $resolvedParams); - } else { - $resolvedParams['menus'] = $this->menuComposer->getMenuFor($menuId, $resolvedParams); - + return $env->render($layout, $resolvedParams); } + $resolvedParams['menus'] = $this->menuComposer->getMenuFor($menuId, $resolvedParams); + + return $env->render($layout, $resolvedParams); } - + + public function getFunctions() + { + return [new TwigFunction( + 'chill_menu', + [$this, 'chillMenu'], + [ + 'is_safe' => ['html'], + 'needs_environment' => true, + ] + ), + ]; + } + public function getName() { return 'chill_menu'; } - public function setContainer(ContainerInterface $container = null) + public function setContainer(?ContainerInterface $container = null) { $this->container = $container; } - } diff --git a/src/Bundle/ChillMainBundle/Search/AbstractSearch.php b/src/Bundle/ChillMainBundle/Search/AbstractSearch.php index 942819a39..e5fa1957e 100644 --- a/src/Bundle/ChillMainBundle/Search/AbstractSearch.php +++ b/src/Bundle/ChillMainBundle/Search/AbstractSearch.php @@ -1,101 +1,89 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Search; -use Chill\MainBundle\Search\SearchInterface; -use Chill\MainBundle\Search\ParsingException; +use DateTime; + +use function strpos; /** * This class implements abstract search with most common responses. - * + * * you should use this abstract class instead of SearchInterface : if the signature of * search interface change, the generic method will be implemented here. - * - * @author Julien Fastré - * */ abstract class AbstractSearch implements SearchInterface { /** - * parse string expected to be a date and transform to a DateTime object - * + * parse string expected to be a date and transform to a DateTime object. + * * @param type $string - * @return \DateTime + * * @throws ParsingException if the date is not parseable + * + * @return DateTime */ public function parseDate($string) { try { - return new \DateTime($string); + return new DateTime($string); } catch (ParsingException $ex) { $exception = new ParsingException('The date is ' . 'not parsable', 0, $ex); + throw $exception; } - } - + /** - * recompose a pattern, retaining only supported terms - * + * recompose a pattern, retaining only supported terms. + * * the outputted string should be used to show users their search - * - * @param array $terms - * @param array $supportedTerms + * * @param string $domain if your domain is NULL, you should set NULL. You should set used domain instead + * * @return string */ - protected function recomposePattern(array $terms, array $supportedTerms, $domain = NULL) + protected function recomposePattern(array $terms, array $supportedTerms, $domain = null) { $recomposed = ''; - - if ($domain !== NULL) - { - $recomposed .= '@'.$domain.' '; + + if (null !== $domain) { + $recomposed .= '@' . $domain . ' '; } - + foreach ($supportedTerms as $term) { - if (array_key_exists($term, $terms) && $term !== '_default') { - $recomposed .= ' '.$term.':'; - $containsSpace = \strpos($terms[$term], " ") !== false; + if (array_key_exists($term, $terms) && '_default' !== $term) { + $recomposed .= ' ' . $term . ':'; + $containsSpace = strpos($terms[$term], ' ') !== false; + if ($containsSpace) { - $recomposed .= "("; + $recomposed .= '('; } - $recomposed .= (mb_stristr(' ', $terms[$term]) === FALSE) ? $terms[$term] : '('.$terms[$term].')'; + $recomposed .= (mb_stristr(' ', $terms[$term]) === false) ? $terms[$term] : '(' . $terms[$term] . ')'; + if ($containsSpace) { - $recomposed .= ")"; + $recomposed .= ')'; } } } - - if ($terms['_default'] !== '') { - $recomposed .= ' '.$terms['_default']; + + if ('' !== $terms['_default']) { + $recomposed .= ' ' . $terms['_default']; } - + //strip first character if empty - if (mb_strcut($recomposed, 0, 1) === ' '){ + if (mb_strcut($recomposed, 0, 1) === ' ') { $recomposed = mb_strcut($recomposed, 1); } - + return $recomposed; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/Search/HasAdvancedSearchFormInterface.php b/src/Bundle/ChillMainBundle/Search/HasAdvancedSearchFormInterface.php index f258a51f8..a06d28b48 100644 --- a/src/Bundle/ChillMainBundle/Search/HasAdvancedSearchFormInterface.php +++ b/src/Bundle/ChillMainBundle/Search/HasAdvancedSearchFormInterface.php @@ -1,34 +1,21 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Search; use Symfony\Component\Form\FormBuilderInterface; -/** - * - * @author Julien Fastré - */ interface HasAdvancedSearchFormInterface extends SearchInterface { public function buildForm(FormBuilderInterface $builder); - + public function convertFormDataToQuery(array $data); - - public function convertTermsToFormData(array $terms) ; - + + public function convertTermsToFormData(array $terms); } diff --git a/src/Bundle/ChillMainBundle/Search/ParsingException.php b/src/Bundle/ChillMainBundle/Search/ParsingException.php index 36d02ab8a..29533d85f 100644 --- a/src/Bundle/ChillMainBundle/Search/ParsingException.php +++ b/src/Bundle/ChillMainBundle/Search/ParsingException.php @@ -1,6 +1,16 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Search; /** * This interface must be implemented on services which provide search results. - * - * @todo : write doc and add a link to documentation - * - * @author Julien Fastré * + * @todo : write doc and add a link to documentation */ interface SearchInterface { - - const SEARCH_PREVIEW_OPTION = '_search_preview'; - /** - * Request parameters contained inside the `add_q` parameters + * Supplementary parameters to the query string. */ - const REQUEST_QUERY_PARAMETERS = '_search_parameters'; - + public const REQUEST_QUERY_KEY_ADD_PARAMETERS = 'add_q'; + /** - * Supplementary parameters to the query string + * Request parameters contained inside the `add_q` parameters. */ - const REQUEST_QUERY_KEY_ADD_PARAMETERS = 'add_q'; + public const REQUEST_QUERY_PARAMETERS = '_search_parameters'; - /** - * return the result in a html string. The string will be inclued (as raw) - * into a global view. - * - * The global view may be : - * {% for result as resultsFromDifferentSearchInterface %} - * {{ result|raw }} - * {% endfor %} - * - * **available options** : - * - SEARCH_PREVIEW_OPTION (boolean) : if renderResult should return a "preview" of - * the results. In this case, a subset of results should be returned, and, - * if the query return more results, a button "see all results" should be - * displayed at the end of the list. - * - * **Interaction between `start` and `limit` and pagination : you should - * take only the given parameters into account; the results from pagination - * should be ignored. (Most of the time, it should be the same). - * - * @param array $terms the string to search - * @param int $start the first result (for pagination) - * @param int $limit the number of result (for pagination) - * @param array $option the options, specific for each search - * @param string $format The format for result - * @return string, an HTML string - */ - public function renderResult(array $terms, $start=0, $limit=50, array $options = array(), $format = 'html'); + public const SEARCH_PREVIEW_OPTION = '_search_preview'; - /** - * we may desactive the search interface by default. in this case, - * the search will be launch and rendered only with "advanced search" - * - * this may be activated/desactived from bundle definition in config.yml - * - * @return bool - */ - public function isActiveByDefault(); + /** + * the order in which the results will appears in the global view. + * + * (this may be eventually defined in config.yml) + * + * @return int + */ + public function getOrder(); - /** - * the order in which the results will appears in the global view - * - * (this may be eventually defined in config.yml) - * - * @return int - */ - public function getOrder(); - - /** - * indicate if the implementation supports the given domain - * - * @return boolean - */ - public function supports($domain, $format); - + /** + * we may desactive the search interface by default. in this case, + * the search will be launch and rendered only with "advanced search". + * + * this may be activated/desactived from bundle definition in config.yml + * + * @return bool + */ + public function isActiveByDefault(); + + /** + * return the result in a html string. The string will be inclued (as raw) + * into a global view. + * + * The global view may be : + * {% for result as resultsFromDifferentSearchInterface %} + * {{ result|raw }} + * {% endfor %} + * + * **available options** : + * - SEARCH_PREVIEW_OPTION (boolean) : if renderResult should return a "preview" of + * the results. In this case, a subset of results should be returned, and, + * if the query return more results, a button "see all results" should be + * displayed at the end of the list. + * + * **Interaction between `start` and `limit` and pagination : you should + * take only the given parameters into account; the results from pagination + * should be ignored. (Most of the time, it should be the same). + * + * @param array $terms the string to search + * @param int $start the first result (for pagination) + * @param int $limit the number of result (for pagination) + * @param string $format The format for result + * + * @return string, an HTML string + */ + public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html'); + + /** + * indicate if the implementation supports the given domain. + * + * @param mixed $domain + * @param mixed $format + * + * @return bool + */ + public function supports($domain, $format); } diff --git a/src/Bundle/ChillMainBundle/Search/SearchProvider.php b/src/Bundle/ChillMainBundle/Search/SearchProvider.php index ca5d169fa..74906f65b 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchProvider.php +++ b/src/Bundle/ChillMainBundle/Search/SearchProvider.php @@ -1,41 +1,78 @@ get('chill_main.search_provider') - * - * the syntax for search string is : - * - domain, which begin with `@`. Example: `@person`. Restrict the search to some - * entities. It may exists multiple search provider for the same domain (example: + * $container->get('chill_main.search_provider'). + * + * the syntax for search string is : + * - domain, which begin with `@`. Example: `@person`. Restrict the search to some + * entities. It may exists multiple search provider for the same domain (example: * a search provider for people which performs regular search, and suggestion search * with phonetical algorithms * - terms, which are the terms of the search. There are terms with argument (example : * `birthdate:2016-04-01` and the default term, which is the search without argument * and without domain. - * */ class SearchProvider { - /** - * - * @var SearchInterface[] - */ - private $searchServices = array(); - - /** - * * @var HasAdvancedSearchForm[] */ - private $hasAdvancedFormSearchServices = array(); - + private $hasAdvancedFormSearchServices = []; + + /** + * store string which must be extracted to find default arguments. + * + * @var string[] + */ + private $mustBeExtracted = []; + + /** + * @var SearchInterface[] + */ + private $searchServices = []; + + public function addSearchService(SearchInterface $service, $name) + { + $this->searchServices[$name] = $service; + + if ($service instanceof HasAdvancedSearchFormInterface) { + $this->hasAdvancedFormSearchServices[$name] = $service; + } + } + + /** + * return search services with a specific name, defined in service + * definition. + * + * @param mixed $name + * + * @throws UnknowSearchNameException if not exists + * + * @return SearchInterface + */ + public function getByName($name) + { + if (isset($this->searchServices[$name])) { + return $this->searchServices[$name]; + } + + throw new UnknowSearchNameException($name); + } + /* * return search services in an array, ordered by * the order key (defined in service definition) @@ -50,39 +87,133 @@ class SearchProvider public function getByOrder() { //sort the array - uasort($this->searchServices, function(SearchInterface $a, SearchInterface $b) { + uasort($this->searchServices, function (SearchInterface $a, SearchInterface $b) { if ($a->getOrder() == $b->getOrder()) { return 0; } + return ($a->getOrder() < $b->getOrder()) ? -1 : 1; }); return $this->searchServices; } - + + /** + * return searchservice with an advanced form, defined in service + * definition. + * + * @param string $name + * + * @throws UnknowSearchNameException + * + * @return HasAdvancedSearchForm + */ + public function getHasAdvancedFormByName($name) + { + if (array_key_exists($name, $this->hasAdvancedFormSearchServices)) { + return $this->hasAdvancedFormSearchServices[$name]; + } + + throw new UnknowSearchNameException($name); + } + public function getHasAdvancedFormSearchServices() { //sort the array - uasort($this->hasAdvancedFormSearchServices, function(SearchInterface $a, SearchInterface $b) { + uasort($this->hasAdvancedFormSearchServices, function (SearchInterface $a, SearchInterface $b) { if ($a->getOrder() == $b->getOrder()) { return 0; } + return ($a->getOrder() < $b->getOrder()) ? -1 : 1; }); return $this->hasAdvancedFormSearchServices; } + public function getResultByName( + $pattern, + $name, + $start = 0, + $limit = 50, + array $options = [], + $format = 'html' + ) { + $terms = $this->parse($pattern); + $search = $this->getByName($name); + + if (null !== $terms['_domain'] && !$search->supports($terms['_domain'], $format)) { + throw new ParsingException('The domain is not supported for the search name'); + } + + return $search->renderResult($terms, $start, $limit, $options, $format); + } + /** - * parse the search string to extract domain and terms - * + * search through services which supports domain and give + * results as an array of resultsfrom different SearchInterface. + * * @param string $pattern + * @param number $start + * @param number $limit + * @param string $format + * + * @throws UnknowSearchDomainException if the domain is unknow + * + * @return array of results from different SearchInterface + */ + public function getSearchResults( + $pattern, + $start = 0, + $limit = 50, + array $options = [], + $format = 'html' + ) { + $terms = $this->parse($pattern); + $results = []; + + //sort searchServices by order + $sortedSearchServices = []; + + foreach ($this->searchServices as $service) { + $sortedSearchServices[$service->getOrder()] = $service; + } + + if (null !== $terms['_domain']) { + foreach ($sortedSearchServices as $service) { + if ($service->supports($terms['_domain'], $format)) { + $results[] = $service->renderResult($terms, $start, $limit, $options); + } + } + + if (count($results) === 0) { + throw new UnknowSearchDomainException($terms['_domain']); + } + } else { // no domain provided, we use default search + foreach ($sortedSearchServices as $service) { + if ($service->isActiveByDefault()) { + $results[] = $service->renderResult($terms, $start, $limit, $options); + } + } + } + + //sort array + ksort($results); + + return $results; + } + + /** + * parse the search string to extract domain and terms. + * + * @param string $pattern + * * @return string[] an array where the keys are _domain, _default (residual terms) or term */ public function parse($pattern) { //reset must be extracted - $this->mustBeExtracted = array(); + $this->mustBeExtracted = []; //filter to lower and remove accentued $filteredPattern = mb_strtolower($this->remove_accents($pattern)); @@ -94,13 +225,27 @@ class SearchProvider } /** - * Extract the domain of the subject - * - * The domain begins with `@`. Example: `@person`, `@report`, .... - * - * @param type $subject + * extract default (residual) arguments. + * + * @param string $subject + * * @return string + */ + private function extractDefault($subject) + { + return trim(str_replace($this->mustBeExtracted, '', $subject)); + } + + /** + * Extract the domain of the subject. + * + * The domain begins with `@`. Example: `@person`, `@report`, .... + * + * @param type $subject + * * @throws ParsingException + * + * @return string */ private function extractDomain(&$subject) { @@ -115,20 +260,22 @@ class SearchProvider $this->mustBeExtracted[] = $terms[0][0]; } - return isset($terms[1][0]) ? $terms[1][0] : NULL; + return $terms[1][0] ?? null; } private function extractTerms(&$subject) { - $terms = array(); + $terms = []; preg_match_all('/([a-z\-]+):([\w\-]+|\([^\(\r\n]+\))/', $subject, $matches); foreach ($matches[2] as $key => $match) { //remove from search pattern $this->mustBeExtracted[] = $matches[0][$key]; //strip parenthesis - if (mb_substr($match, 0, 1) === '(' && - mb_substr($match, mb_strlen($match) - 1) === ')') { + if ( + mb_substr($match, 0, 1) === '(' + && mb_substr($match, mb_strlen($match) - 1) === ')' + ) { $match = trim(mb_substr($match, 1, mb_strlen($match) - 2)); } $terms[$matches[1][$key]] = $match; @@ -137,128 +284,6 @@ class SearchProvider return $terms; } - /** - * store string which must be extracted to find default arguments - * - * @var string[] - */ - private $mustBeExtracted = array(); - - /** - * extract default (residual) arguments - * - * @param string $subject - * @return string - */ - private function extractDefault($subject) - { - return trim(str_replace($this->mustBeExtracted, '', $subject)); - } - - /** - * search through services which supports domain and give - * results as an array of resultsfrom different SearchInterface - * - * @param string $pattern - * @param number $start - * @param number $limit - * @param array $options - * @param string $format - * @return array of results from different SearchInterface - * @throws UnknowSearchDomainException if the domain is unknow - */ - public function getSearchResults($pattern, $start = 0, $limit = 50, - array $options = array(), $format = 'html') - { - $terms = $this->parse($pattern); - $results = array(); - - //sort searchServices by order - $sortedSearchServices = array(); - foreach($this->searchServices as $service) { - $sortedSearchServices[$service->getOrder()] = $service; - } - - if ($terms['_domain'] !== NULL) { - foreach ($sortedSearchServices as $service) { - if ($service->supports($terms['_domain'], $format)) { - $results[] = $service->renderResult($terms, $start, $limit, $options); - } - } - - if (count($results) === 0) { - throw new UnknowSearchDomainException($terms['_domain']); - } - } else { // no domain provided, we use default search - foreach($sortedSearchServices as $service) { - if ($service->isActiveByDefault()) { - $results[] = $service->renderResult($terms, $start, $limit, $options); - } - } - } - - //sort array - ksort($results); - - return $results; - } - - public function getResultByName($pattern, $name, $start = 0, $limit = 50, - array $options = array(), $format = 'html') - { - $terms = $this->parse($pattern); - $search = $this->getByName($name); - - if ($terms['_domain'] !== NULL && !$search->supports($terms['_domain'], $format)) - { - throw new ParsingException("The domain is not supported for the search name"); - } - - return $search->renderResult($terms, $start, $limit, $options, $format); - } - - /** - * return search services with a specific name, defined in service - * definition. - * - * @return SearchInterface - * @throws UnknowSearchNameException if not exists - */ - public function getByName($name) - { - if (isset($this->searchServices[$name])) { - return $this->searchServices[$name]; - } else { - throw new UnknowSearchNameException($name); - } - } - - /** - * return searchservice with an advanced form, defined in service - * definition. - * - * @param string $name - * @return HasAdvancedSearchForm - * @throws UnknowSearchNameException - */ - public function getHasAdvancedFormByName($name) - { - if (\array_key_exists($name, $this->hasAdvancedFormSearchServices)) { - return $this->hasAdvancedFormSearchServices[$name]; - } else { - throw new UnknowSearchNameException($name); - } - } - - public function addSearchService(SearchInterface $service, $name) - { - $this->searchServices[$name] = $service; - - if ($service instanceof HasAdvancedSearchFormInterface) { - $this->hasAdvancedFormSearchServices[$name] = $service; - } - } - /** * Converts all accent characters to ASCII characters. * @@ -267,191 +292,194 @@ class SearchProvider * Imported from wordpress : https://core.trac.wordpress.org/browser/tags/4.1/src/wp-includes/formatting.php?order=name * * @param string $string Text that might have accent characters + * * @return string Filtered string with replaced "nice" characters. + * * @license GNU GPLv2 : https://core.trac.wordpress.org/browser/tags/4.1/src/license.txt */ private function remove_accents($string) { - if (!preg_match('/[\x80-\xff]/', $string)) + if (!preg_match('/[\x80-\xff]/', $string)) { return $string; + } //if ($this->seems_utf8($string)) { // remove from wordpress: we use only UTF-8 if (true) { - $chars = array( - // Decompositions for Latin-1 Supplement - chr(194) . chr(170) => 'a', chr(194) . chr(186) => 'o', - chr(195) . chr(128) => 'A', chr(195) . chr(129) => 'A', - chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A', - chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A', - chr(195) . chr(134) => 'AE', chr(195) . chr(135) => 'C', - chr(195) . chr(136) => 'E', chr(195) . chr(137) => 'E', - chr(195) . chr(138) => 'E', chr(195) . chr(139) => 'E', - chr(195) . chr(140) => 'I', chr(195) . chr(141) => 'I', - chr(195) . chr(142) => 'I', chr(195) . chr(143) => 'I', - chr(195) . chr(144) => 'D', chr(195) . chr(145) => 'N', - chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O', - chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O', - chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U', - chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U', - chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y', - chr(195) . chr(158) => 'TH', chr(195) . chr(159) => 's', - chr(195) . chr(160) => 'a', chr(195) . chr(161) => 'a', - chr(195) . chr(162) => 'a', chr(195) . chr(163) => 'a', - chr(195) . chr(164) => 'a', chr(195) . chr(165) => 'a', - chr(195) . chr(166) => 'ae', chr(195) . chr(167) => 'c', - chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e', - chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e', - chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i', - chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i', - chr(195) . chr(176) => 'd', chr(195) . chr(177) => 'n', - chr(195) . chr(178) => 'o', chr(195) . chr(179) => 'o', - chr(195) . chr(180) => 'o', chr(195) . chr(181) => 'o', - chr(195) . chr(182) => 'o', chr(195) . chr(184) => 'o', - chr(195) . chr(185) => 'u', chr(195) . chr(186) => 'u', - chr(195) . chr(187) => 'u', chr(195) . chr(188) => 'u', - chr(195) . chr(189) => 'y', chr(195) . chr(190) => 'th', - chr(195) . chr(191) => 'y', chr(195) . chr(152) => 'O', - // Decompositions for Latin Extended-A - chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a', - chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a', - chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a', - chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c', - chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c', - chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c', - chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c', - chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd', - chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd', - chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e', - chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e', - chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e', - chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e', - chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e', - chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g', - chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g', - chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g', - chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g', - chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h', - chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h', - chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i', - chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i', - chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i', - chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i', - chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i', - chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij', - chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j', - chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k', - chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L', - chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L', - chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L', - chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L', - chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L', - chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N', - chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N', - chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N', - chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N', - chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N', - chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o', - chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o', - chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o', - chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe', - chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r', - chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r', - chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r', - chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's', - chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's', - chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's', - chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's', - chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't', - chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't', - chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't', - chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u', - chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u', - chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u', - chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u', - chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u', - chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u', - chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w', - chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y', - chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z', - chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z', - chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z', - chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's', - // Decompositions for Latin Extended-B - chr(200) . chr(152) => 'S', chr(200) . chr(153) => 's', - chr(200) . chr(154) => 'T', chr(200) . chr(155) => 't', - // Euro Sign - chr(226) . chr(130) . chr(172) => 'E', - // GBP (Pound) Sign - chr(194) . chr(163) => '', - // Vowels with diacritic (Vietnamese) - // unmarked - chr(198) . chr(160) => 'O', chr(198) . chr(161) => 'o', - chr(198) . chr(175) => 'U', chr(198) . chr(176) => 'u', - // grave accent - chr(225) . chr(186) . chr(166) => 'A', chr(225) . chr(186) . chr(167) => 'a', - chr(225) . chr(186) . chr(176) => 'A', chr(225) . chr(186) . chr(177) => 'a', - chr(225) . chr(187) . chr(128) => 'E', chr(225) . chr(187) . chr(129) => 'e', - chr(225) . chr(187) . chr(146) => 'O', chr(225) . chr(187) . chr(147) => 'o', - chr(225) . chr(187) . chr(156) => 'O', chr(225) . chr(187) . chr(157) => 'o', - chr(225) . chr(187) . chr(170) => 'U', chr(225) . chr(187) . chr(171) => 'u', - chr(225) . chr(187) . chr(178) => 'Y', chr(225) . chr(187) . chr(179) => 'y', - // hook - chr(225) . chr(186) . chr(162) => 'A', chr(225) . chr(186) . chr(163) => 'a', - chr(225) . chr(186) . chr(168) => 'A', chr(225) . chr(186) . chr(169) => 'a', - chr(225) . chr(186) . chr(178) => 'A', chr(225) . chr(186) . chr(179) => 'a', - chr(225) . chr(186) . chr(186) => 'E', chr(225) . chr(186) . chr(187) => 'e', - chr(225) . chr(187) . chr(130) => 'E', chr(225) . chr(187) . chr(131) => 'e', - chr(225) . chr(187) . chr(136) => 'I', chr(225) . chr(187) . chr(137) => 'i', - chr(225) . chr(187) . chr(142) => 'O', chr(225) . chr(187) . chr(143) => 'o', - chr(225) . chr(187) . chr(148) => 'O', chr(225) . chr(187) . chr(149) => 'o', - chr(225) . chr(187) . chr(158) => 'O', chr(225) . chr(187) . chr(159) => 'o', - chr(225) . chr(187) . chr(166) => 'U', chr(225) . chr(187) . chr(167) => 'u', - chr(225) . chr(187) . chr(172) => 'U', chr(225) . chr(187) . chr(173) => 'u', - chr(225) . chr(187) . chr(182) => 'Y', chr(225) . chr(187) . chr(183) => 'y', - // tilde - chr(225) . chr(186) . chr(170) => 'A', chr(225) . chr(186) . chr(171) => 'a', - chr(225) . chr(186) . chr(180) => 'A', chr(225) . chr(186) . chr(181) => 'a', - chr(225) . chr(186) . chr(188) => 'E', chr(225) . chr(186) . chr(189) => 'e', - chr(225) . chr(187) . chr(132) => 'E', chr(225) . chr(187) . chr(133) => 'e', - chr(225) . chr(187) . chr(150) => 'O', chr(225) . chr(187) . chr(151) => 'o', - chr(225) . chr(187) . chr(160) => 'O', chr(225) . chr(187) . chr(161) => 'o', - chr(225) . chr(187) . chr(174) => 'U', chr(225) . chr(187) . chr(175) => 'u', - chr(225) . chr(187) . chr(184) => 'Y', chr(225) . chr(187) . chr(185) => 'y', - // acute accent - chr(225) . chr(186) . chr(164) => 'A', chr(225) . chr(186) . chr(165) => 'a', - chr(225) . chr(186) . chr(174) => 'A', chr(225) . chr(186) . chr(175) => 'a', - chr(225) . chr(186) . chr(190) => 'E', chr(225) . chr(186) . chr(191) => 'e', - chr(225) . chr(187) . chr(144) => 'O', chr(225) . chr(187) . chr(145) => 'o', - chr(225) . chr(187) . chr(154) => 'O', chr(225) . chr(187) . chr(155) => 'o', - chr(225) . chr(187) . chr(168) => 'U', chr(225) . chr(187) . chr(169) => 'u', - // dot below - chr(225) . chr(186) . chr(160) => 'A', chr(225) . chr(186) . chr(161) => 'a', - chr(225) . chr(186) . chr(172) => 'A', chr(225) . chr(186) . chr(173) => 'a', - chr(225) . chr(186) . chr(182) => 'A', chr(225) . chr(186) . chr(183) => 'a', - chr(225) . chr(186) . chr(184) => 'E', chr(225) . chr(186) . chr(185) => 'e', - chr(225) . chr(187) . chr(134) => 'E', chr(225) . chr(187) . chr(135) => 'e', - chr(225) . chr(187) . chr(138) => 'I', chr(225) . chr(187) . chr(139) => 'i', - chr(225) . chr(187) . chr(140) => 'O', chr(225) . chr(187) . chr(141) => 'o', - chr(225) . chr(187) . chr(152) => 'O', chr(225) . chr(187) . chr(153) => 'o', - chr(225) . chr(187) . chr(162) => 'O', chr(225) . chr(187) . chr(163) => 'o', - chr(225) . chr(187) . chr(164) => 'U', chr(225) . chr(187) . chr(165) => 'u', - chr(225) . chr(187) . chr(176) => 'U', chr(225) . chr(187) . chr(177) => 'u', - chr(225) . chr(187) . chr(180) => 'Y', chr(225) . chr(187) . chr(181) => 'y', - // Vowels with diacritic (Chinese, Hanyu Pinyin) - chr(201) . chr(145) => 'a', - // macron - chr(199) . chr(149) => 'U', chr(199) . chr(150) => 'u', - // acute accent - chr(199) . chr(151) => 'U', chr(199) . chr(152) => 'u', - // caron - chr(199) . chr(141) => 'A', chr(199) . chr(142) => 'a', - chr(199) . chr(143) => 'I', chr(199) . chr(144) => 'i', - chr(199) . chr(145) => 'O', chr(199) . chr(146) => 'o', - chr(199) . chr(147) => 'U', chr(199) . chr(148) => 'u', - chr(199) . chr(153) => 'U', chr(199) . chr(154) => 'u', - // grave accent - chr(199) . chr(155) => 'U', chr(199) . chr(156) => 'u', - ); + $chars = [ + // Decompositions for Latin-1 Supplement + chr(194) . chr(170) => 'a', chr(194) . chr(186) => 'o', + chr(195) . chr(128) => 'A', chr(195) . chr(129) => 'A', + chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A', + chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A', + chr(195) . chr(134) => 'AE', chr(195) . chr(135) => 'C', + chr(195) . chr(136) => 'E', chr(195) . chr(137) => 'E', + chr(195) . chr(138) => 'E', chr(195) . chr(139) => 'E', + chr(195) . chr(140) => 'I', chr(195) . chr(141) => 'I', + chr(195) . chr(142) => 'I', chr(195) . chr(143) => 'I', + chr(195) . chr(144) => 'D', chr(195) . chr(145) => 'N', + chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O', + chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O', + chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U', + chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U', + chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y', + chr(195) . chr(158) => 'TH', chr(195) . chr(159) => 's', + chr(195) . chr(160) => 'a', chr(195) . chr(161) => 'a', + chr(195) . chr(162) => 'a', chr(195) . chr(163) => 'a', + chr(195) . chr(164) => 'a', chr(195) . chr(165) => 'a', + chr(195) . chr(166) => 'ae', chr(195) . chr(167) => 'c', + chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e', + chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e', + chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i', + chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i', + chr(195) . chr(176) => 'd', chr(195) . chr(177) => 'n', + chr(195) . chr(178) => 'o', chr(195) . chr(179) => 'o', + chr(195) . chr(180) => 'o', chr(195) . chr(181) => 'o', + chr(195) . chr(182) => 'o', chr(195) . chr(184) => 'o', + chr(195) . chr(185) => 'u', chr(195) . chr(186) => 'u', + chr(195) . chr(187) => 'u', chr(195) . chr(188) => 'u', + chr(195) . chr(189) => 'y', chr(195) . chr(190) => 'th', + chr(195) . chr(191) => 'y', chr(195) . chr(152) => 'O', + // Decompositions for Latin Extended-A + chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a', + chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a', + chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a', + chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c', + chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c', + chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c', + chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c', + chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd', + chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd', + chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e', + chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e', + chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e', + chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e', + chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e', + chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g', + chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g', + chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g', + chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g', + chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h', + chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h', + chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i', + chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i', + chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i', + chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i', + chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i', + chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij', + chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j', + chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k', + chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L', + chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L', + chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L', + chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L', + chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L', + chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N', + chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N', + chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N', + chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N', + chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N', + chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o', + chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o', + chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o', + chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe', + chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r', + chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r', + chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r', + chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's', + chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's', + chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's', + chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's', + chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't', + chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't', + chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't', + chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u', + chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u', + chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u', + chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u', + chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u', + chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u', + chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w', + chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y', + chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z', + chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z', + chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z', + chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's', + // Decompositions for Latin Extended-B + chr(200) . chr(152) => 'S', chr(200) . chr(153) => 's', + chr(200) . chr(154) => 'T', chr(200) . chr(155) => 't', + // Euro Sign + chr(226) . chr(130) . chr(172) => 'E', + // GBP (Pound) Sign + chr(194) . chr(163) => '', + // Vowels with diacritic (Vietnamese) + // unmarked + chr(198) . chr(160) => 'O', chr(198) . chr(161) => 'o', + chr(198) . chr(175) => 'U', chr(198) . chr(176) => 'u', + // grave accent + chr(225) . chr(186) . chr(166) => 'A', chr(225) . chr(186) . chr(167) => 'a', + chr(225) . chr(186) . chr(176) => 'A', chr(225) . chr(186) . chr(177) => 'a', + chr(225) . chr(187) . chr(128) => 'E', chr(225) . chr(187) . chr(129) => 'e', + chr(225) . chr(187) . chr(146) => 'O', chr(225) . chr(187) . chr(147) => 'o', + chr(225) . chr(187) . chr(156) => 'O', chr(225) . chr(187) . chr(157) => 'o', + chr(225) . chr(187) . chr(170) => 'U', chr(225) . chr(187) . chr(171) => 'u', + chr(225) . chr(187) . chr(178) => 'Y', chr(225) . chr(187) . chr(179) => 'y', + // hook + chr(225) . chr(186) . chr(162) => 'A', chr(225) . chr(186) . chr(163) => 'a', + chr(225) . chr(186) . chr(168) => 'A', chr(225) . chr(186) . chr(169) => 'a', + chr(225) . chr(186) . chr(178) => 'A', chr(225) . chr(186) . chr(179) => 'a', + chr(225) . chr(186) . chr(186) => 'E', chr(225) . chr(186) . chr(187) => 'e', + chr(225) . chr(187) . chr(130) => 'E', chr(225) . chr(187) . chr(131) => 'e', + chr(225) . chr(187) . chr(136) => 'I', chr(225) . chr(187) . chr(137) => 'i', + chr(225) . chr(187) . chr(142) => 'O', chr(225) . chr(187) . chr(143) => 'o', + chr(225) . chr(187) . chr(148) => 'O', chr(225) . chr(187) . chr(149) => 'o', + chr(225) . chr(187) . chr(158) => 'O', chr(225) . chr(187) . chr(159) => 'o', + chr(225) . chr(187) . chr(166) => 'U', chr(225) . chr(187) . chr(167) => 'u', + chr(225) . chr(187) . chr(172) => 'U', chr(225) . chr(187) . chr(173) => 'u', + chr(225) . chr(187) . chr(182) => 'Y', chr(225) . chr(187) . chr(183) => 'y', + // tilde + chr(225) . chr(186) . chr(170) => 'A', chr(225) . chr(186) . chr(171) => 'a', + chr(225) . chr(186) . chr(180) => 'A', chr(225) . chr(186) . chr(181) => 'a', + chr(225) . chr(186) . chr(188) => 'E', chr(225) . chr(186) . chr(189) => 'e', + chr(225) . chr(187) . chr(132) => 'E', chr(225) . chr(187) . chr(133) => 'e', + chr(225) . chr(187) . chr(150) => 'O', chr(225) . chr(187) . chr(151) => 'o', + chr(225) . chr(187) . chr(160) => 'O', chr(225) . chr(187) . chr(161) => 'o', + chr(225) . chr(187) . chr(174) => 'U', chr(225) . chr(187) . chr(175) => 'u', + chr(225) . chr(187) . chr(184) => 'Y', chr(225) . chr(187) . chr(185) => 'y', + // acute accent + chr(225) . chr(186) . chr(164) => 'A', chr(225) . chr(186) . chr(165) => 'a', + chr(225) . chr(186) . chr(174) => 'A', chr(225) . chr(186) . chr(175) => 'a', + chr(225) . chr(186) . chr(190) => 'E', chr(225) . chr(186) . chr(191) => 'e', + chr(225) . chr(187) . chr(144) => 'O', chr(225) . chr(187) . chr(145) => 'o', + chr(225) . chr(187) . chr(154) => 'O', chr(225) . chr(187) . chr(155) => 'o', + chr(225) . chr(187) . chr(168) => 'U', chr(225) . chr(187) . chr(169) => 'u', + // dot below + chr(225) . chr(186) . chr(160) => 'A', chr(225) . chr(186) . chr(161) => 'a', + chr(225) . chr(186) . chr(172) => 'A', chr(225) . chr(186) . chr(173) => 'a', + chr(225) . chr(186) . chr(182) => 'A', chr(225) . chr(186) . chr(183) => 'a', + chr(225) . chr(186) . chr(184) => 'E', chr(225) . chr(186) . chr(185) => 'e', + chr(225) . chr(187) . chr(134) => 'E', chr(225) . chr(187) . chr(135) => 'e', + chr(225) . chr(187) . chr(138) => 'I', chr(225) . chr(187) . chr(139) => 'i', + chr(225) . chr(187) . chr(140) => 'O', chr(225) . chr(187) . chr(141) => 'o', + chr(225) . chr(187) . chr(152) => 'O', chr(225) . chr(187) . chr(153) => 'o', + chr(225) . chr(187) . chr(162) => 'O', chr(225) . chr(187) . chr(163) => 'o', + chr(225) . chr(187) . chr(164) => 'U', chr(225) . chr(187) . chr(165) => 'u', + chr(225) . chr(187) . chr(176) => 'U', chr(225) . chr(187) . chr(177) => 'u', + chr(225) . chr(187) . chr(180) => 'Y', chr(225) . chr(187) . chr(181) => 'y', + // Vowels with diacritic (Chinese, Hanyu Pinyin) + chr(201) . chr(145) => 'a', + // macron + chr(199) . chr(149) => 'U', chr(199) . chr(150) => 'u', + // acute accent + chr(199) . chr(151) => 'U', chr(199) . chr(152) => 'u', + // caron + chr(199) . chr(141) => 'A', chr(199) . chr(142) => 'a', + chr(199) . chr(143) => 'I', chr(199) . chr(144) => 'i', + chr(199) . chr(145) => 'O', chr(199) . chr(146) => 'o', + chr(199) . chr(147) => 'U', chr(199) . chr(148) => 'u', + chr(199) . chr(153) => 'U', chr(199) . chr(154) => 'u', + // grave accent + chr(199) . chr(155) => 'U', chr(199) . chr(156) => 'u', + ]; // Used for locale-specific rules /* remove from wordpress @@ -477,7 +505,7 @@ class SearchProvider $string = strtr($string, $chars); } /* remove from wordpress: we use only utf 8 * else { - + // Assume ISO-8859-1 if not UTF-8 $chars['in'] = chr(128) . chr(131) . chr(138) . chr(142) . chr(154) . chr(158) . chr(159) . chr(162) . chr(165) . chr(181) . chr(192) . chr(193) . chr(194) @@ -500,5 +528,4 @@ class SearchProvider return $string; } - } diff --git a/src/Bundle/ChillMainBundle/Search/UnknowSearchDomainException.php b/src/Bundle/ChillMainBundle/Search/UnknowSearchDomainException.php index 5c09ebe39..a54ca8e1c 100644 --- a/src/Bundle/ChillMainBundle/Search/UnknowSearchDomainException.php +++ b/src/Bundle/ChillMainBundle/Search/UnknowSearchDomainException.php @@ -1,42 +1,30 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Search; +use Exception; + /** - * Throw by search provider when the search name is not found - * - * @author Julien Fastré + * Throw by search provider when the search name is not found. */ -class UnknowSearchDomainException extends \Exception +class UnknowSearchDomainException extends Exception { - private $domain; - + public function __construct($domain) { - parent::__construct( "The domain $domain is not found"); + parent::__construct("The domain {$domain} is not found"); $this->domain = $domain; } - - public function getDomain() + + public function getDomain() { return $this->domain; } diff --git a/src/Bundle/ChillMainBundle/Search/UnknowSearchNameException.php b/src/Bundle/ChillMainBundle/Search/UnknowSearchNameException.php index 989fdbec5..8b7864a77 100644 --- a/src/Bundle/ChillMainBundle/Search/UnknowSearchNameException.php +++ b/src/Bundle/ChillMainBundle/Search/UnknowSearchNameException.php @@ -1,41 +1,29 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Search; +use Exception; + /** - * Throw by search provider when the search name is not found - * - * @author Julien Fastré + * Throw by search provider when the search name is not found. */ -class UnknowSearchNameException extends \Exception +class UnknowSearchNameException extends Exception { - private $name; - + public function __construct($name) { - parent::__construct( "No module search supports with the name $name"); + parent::__construct("No module search supports with the name {$name}"); $this->name = $name; } - + public function getName() { return $this->name; diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php index 842fc5ecc..c6ec2189e 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/AbstractChillVoter.php @@ -1,55 +1,46 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Security\Authorization; -use Symfony\Component\Security\Core\Authorization\Voter\Voter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + +use function get_class; +use function in_array; /** - * Voter for Chill software. - * + * Voter for Chill software. + * * This abstract Voter provide generic methods to handle object specific to Chill - * - * - * @author Julien Fastré */ abstract class AbstractChillVoter extends Voter implements ChillVoterInterface { protected function supports($attribute, $subject) { - @trigger_error('This voter should implements the new `supports` ' + @trigger_error( + 'This voter should implements the new `supports` ' . 'methods introduced by Symfony 3.0, and do not rely on ' - . 'getSupportedAttributes and getSupportedClasses methods.', - E_USER_DEPRECATED); + . 'getSupportedAttributes and getSupportedClasses methods.', + E_USER_DEPRECATED + ); - return \in_array($attribute, $this->getSupportedAttributes($attribute)) - && \in_array(\get_class($subject), $this->getSupportedClasses()); + return in_array($attribute, $this->getSupportedAttributes($attribute)) + && in_array(get_class($subject), $this->getSupportedClasses()); } - + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { @trigger_error('This voter should implements the new `voteOnAttribute` ' . 'methods introduced by Symfony 3.0, and do not rely on ' . 'isGranted method', E_USER_DEPRECATED); - + return $this->isGranted($attribute, $subject, $token->getUser()); } - } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php index ed2dd499d..8e997015a 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/AuthorizationHelper.php @@ -1,245 +1,74 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Security\Authorization; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; -use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; -use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Security\RoleProvider; +use Chill\MainBundle\Entity\User; use Doctrine\ORM\EntityManagerInterface; -use Chill\MainBundle\Entity\GroupCenter; -use Chill\MainBundle\Entity\RoleScope; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; + +use function array_keys; +use function array_map; /** - * Helper for authorizations. - * - * Provides methods for user and entities information. + * Helper for authorizations. * - * @author Julien Fastré + * Provides methods for user and entities information. */ class AuthorizationHelper { /** - * - * @var RoleHierarchyInterface + * @var EntityManagerInterface */ - protected $roleHierarchy; - + protected $em; + /** - * The role in a hierarchy, given by the parameter + * The role in a hierarchy, given by the parameter * `security.role_hierarchy.roles` from the container. * * @var string[] */ protected $hierarchy; - + /** - * - * @var EntityManagerInterface + * @var RoleHierarchyInterface */ - protected $em; - + protected $roleHierarchy; + public function __construct( RoleHierarchyInterface $roleHierarchy, $hierarchy, EntityManagerInterface $em ) { $this->roleHierarchy = $roleHierarchy; - $this->hierarchy = $hierarchy; + $this->hierarchy = $hierarchy; $this->em = $em; } - - /** - * Determines if a user is active on this center - * - * @param User $user - * @param Center $center - * @return bool - */ - public function userCanReachCenter(User $user, Center $center) - { - foreach ($user->getGroupCenters() as $groupCenter) { - if ($center->getId() === $groupCenter->getCenter()->getId()) { - - return true; - } - } - - return false; - } - - /** - * - * Determines if the user has access to the given entity. - * - * if the entity implements Chill\MainBundle\Entity\HasScopeInterface, - * the scope is taken into account. - * - * @param User $user - * @param HasCenterInterface $entity the entity may also implement HasScopeInterface - * @param string|Role $attribute - * @return boolean true if the user has access - */ - public function userHasAccess(User $user, HasCenterInterface $entity, $attribute) - { - - $center = $entity->getCenter(); - - if (!$this->userCanReachCenter($user, $center)) { - return false; - } - - $role = ($attribute instanceof Role) ? $attribute : new Role($attribute); - - foreach ($user->getGroupCenters() as $groupCenter){ - //filter on center - if ($groupCenter->getCenter()->getId() === $entity->getCenter()->getId()) { - $permissionGroup = $groupCenter->getPermissionsGroup(); - //iterate on roleScopes - foreach($permissionGroup->getRoleScopes() as $roleScope) { - //check that the role allow to reach the required role - if ($this->isRoleReached($role, - new Role($roleScope->getRole()))){ - //if yes, we have a right on something... - // perform check on scope if necessary - if ($entity instanceof HasScopeInterface) { - $scope = $entity->getScope(); - if ($scope === NULL) { - return true; - } - if ($scope->getId() === $roleScope - ->getScope()->getId()) { - return true; - } - } else { - return true; - } - } - } - - } - } - - return false; - } - - /** - * Get reachable Centers for the given user, role, - * and optionnaly Scope - * - * @param User $user - * @param Role $role - * @param null|Scope $scope - * @return Center[] - */ - public function getReachableCenters(User $user, Role $role, Scope $scope = null) - { - $centers = array(); - - foreach ($user->getGroupCenters() as $groupCenter){ - $permissionGroup = $groupCenter->getPermissionsGroup(); - //iterate on roleScopes - foreach($permissionGroup->getRoleScopes() as $roleScope) { - //check that the role is in the reachable roles - if ($this->isRoleReached($role, - new Role($roleScope->getRole()))) { - if ($scope === null) { - $centers[] = $groupCenter->getCenter(); - break 1; - } else { - if ($scope->getId() == $roleScope->getScope()->getId()){ - $centers[] = $groupCenter->getCenter(); - break 1; - } - } - } - } - - } - - return $centers; - } - - /** - * Return all reachable scope for a given user, center and role - * - * @deprecated Use getReachableCircles - * - * @param User $user - * @param Role $role - * @param Center $center - * @return Scope[] - */ - public function getReachableScopes(User $user, Role $role, Center $center) - { - return $this->getReachableCircles($user, $role, $center); - } - - /** - * Return all reachable circle for a given user, center and role - * - * @param User $user - * @param Role $role - * @param Center $center - * @return Scope[] - */ - public function getReachableCircles(User $user, Role $role, Center $center) - { - $scopes = array(); - - foreach ($user->getGroupCenters() as $groupCenter){ - if ($center->getId() === $groupCenter->getCenter()->getId()) { - //iterate on permissionGroup - $permissionGroup = $groupCenter->getPermissionsGroup(); - //iterate on roleScopes - foreach($permissionGroup->getRoleScopes() as $roleScope) { - //check that the role is in the reachable roles - if ($this->isRoleReached($role, - new Role($roleScope->getRole()))) { - $scopes[] = $roleScope->getScope(); - } - } - } - } - - return $scopes; - } - /** - * - * @param Role $role - * @param Center $center * @param Scope $circle + * * @return Users */ - public function findUsersReaching(Role $role, Center $center, Scope $circle = null) + public function findUsersReaching(Role $role, Center $center, ?Scope $circle = null) { $parents = $this->getParentRoles($role); $parents[] = $role; - $parentRolesString = \array_map(function(Role $r) { return $r->getRole(); }, $parents); - + $parentRolesString = array_map(function (Role $r) { + return $r->getRole(); + }, $parents); + $qb = $this->em->createQueryBuilder(); $qb ->select('u') @@ -248,61 +77,217 @@ class AuthorizationHelper ->join('gc.permissionsGroup', 'pg') ->join('pg.roleScopes', 'rs') ->where('gc.center = :center') - ->andWhere($qb->expr()->in('rs.role', $parentRolesString)) - ; - + ->andWhere($qb->expr()->in('rs.role', $parentRolesString)); + $qb->setParameter('center', $center); - - if ($circle !== null) { + + if (null !== $circle) { $qb->andWhere('rs.scope = :circle') - ->setParameter('circle', $circle) - ; + ->setParameter('circle', $circle); } - + return $qb->getQuery()->getResult(); } - + /** - * Test if a parent role may give access to a given child role - * - * @param Role $childRole The role we want to test if he is reachable - * @param Role $parentRole The role which should give access to $childRole - * @return boolean true if the child role is granted by parent role - */ - protected function isRoleReached(Role $childRole, Role $parentRole) - { - $reachableRoles = $this->roleHierarchy - ->getReachableRoles([$parentRole]); - - return in_array($childRole, $reachableRoles); - } - - /** - * Return all the role which give access to the given role. Only the role + * Return all the role which give access to the given role. Only the role * which are registered into Chill are taken into account. - * - * @param Role $role + * * @return Role[] the role which give access to the given $role */ public function getParentRoles(Role $role) { $parentRoles = []; // transform the roles from role hierarchy from string to Role - $roles = \array_map( - function($string) { - return new Role($string); - }, - \array_keys($this->hierarchy) - ); - + $roles = array_map( + function ($string) { + return new Role($string); + }, + array_keys($this->hierarchy) + ); + foreach ($roles as $r) { $childRoles = $this->roleHierarchy->getReachableRoleNames([$r->getRole()]); - + if (\in_array($role, $childRoles)) { $parentRoles[] = $r; } } - + return $parentRoles; } + + /** + * Get reachable Centers for the given user, role, + * and optionnaly Scope. + * + * @return Center[] + */ + public function getReachableCenters(User $user, Role $role, ?Scope $scope = null) + { + $centers = []; + + foreach ($user->getGroupCenters() as $groupCenter) { + $permissionGroup = $groupCenter->getPermissionsGroup(); + //iterate on roleScopes + foreach ($permissionGroup->getRoleScopes() as $roleScope) { + //check that the role is in the reachable roles + if ( + $this->isRoleReached( + $role, + new Role($roleScope->getRole()) + ) + ) { + if (null === $scope) { + $centers[] = $groupCenter->getCenter(); + + break; + } + + if ($scope->getId() == $roleScope->getScope()->getId()) { + $centers[] = $groupCenter->getCenter(); + + break; + } + } + } + } + + return $centers; + } + + /** + * Return all reachable circle for a given user, center and role. + * + * @return Scope[] + */ + public function getReachableCircles(User $user, Role $role, Center $center) + { + $scopes = []; + + foreach ($user->getGroupCenters() as $groupCenter) { + if ($center->getId() === $groupCenter->getCenter()->getId()) { + //iterate on permissionGroup + $permissionGroup = $groupCenter->getPermissionsGroup(); + //iterate on roleScopes + foreach ($permissionGroup->getRoleScopes() as $roleScope) { + //check that the role is in the reachable roles + if ( + $this->isRoleReached( + $role, + new Role($roleScope->getRole()) + ) + ) { + $scopes[] = $roleScope->getScope(); + } + } + } + } + + return $scopes; + } + + /** + * Return all reachable scope for a given user, center and role. + * + * @deprecated Use getReachableCircles + * + * @return Scope[] + */ + public function getReachableScopes(User $user, Role $role, Center $center) + { + return $this->getReachableCircles($user, $role, $center); + } + + /** + * Determines if a user is active on this center. + * + * @return bool + */ + public function userCanReachCenter(User $user, Center $center) + { + foreach ($user->getGroupCenters() as $groupCenter) { + if ($center->getId() === $groupCenter->getCenter()->getId()) { + return true; + } + } + + return false; + } + + /** + * Determines if the user has access to the given entity. + * + * if the entity implements Chill\MainBundle\Entity\HasScopeInterface, + * the scope is taken into account. + * + * @param HasCenterInterface $entity the entity may also implement HasScopeInterface + * @param Role|string $attribute + * + * @return bool true if the user has access + */ + public function userHasAccess(User $user, HasCenterInterface $entity, $attribute) + { + $center = $entity->getCenter(); + + if (!$this->userCanReachCenter($user, $center)) { + return false; + } + + $role = ($attribute instanceof Role) ? $attribute : new Role($attribute); + + foreach ($user->getGroupCenters() as $groupCenter) { + //filter on center + if ($groupCenter->getCenter()->getId() === $entity->getCenter()->getId()) { + $permissionGroup = $groupCenter->getPermissionsGroup(); + //iterate on roleScopes + foreach ($permissionGroup->getRoleScopes() as $roleScope) { + //check that the role allow to reach the required role + if ( + $this->isRoleReached( + $role, + new Role($roleScope->getRole()) + ) + ) { + //if yes, we have a right on something... + // perform check on scope if necessary + if ($entity instanceof HasScopeInterface) { + $scope = $entity->getScope(); + + if (null === $scope) { + return true; + } + + if ( + $scope->getId() === $roleScope + ->getScope()->getId() + ) { + return true; + } + } else { + return true; + } + } + } + } + } + + return false; + } + + /** + * Test if a parent role may give access to a given child role. + * + * @param Role $childRole The role we want to test if he is reachable + * @param Role $parentRole The role which should give access to $childRole + * + * @return bool true if the child role is granted by parent role + */ + protected function isRoleReached(Role $childRole, Role $parentRole) + { + $reachableRoles = $this->roleHierarchy + ->getReachableRoles([$parentRole]); + + return in_array($childRole, $reachableRoles); + } } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php index 39af35706..caf9af490 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/ChillExportVoter.php @@ -1,51 +1,36 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Security\Authorization; - -use Symfony\Component\Security\Core\Authorization\Voter\Voter; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Role\Role; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Security\Authorization; + +use Chill\MainBundle\Entity\User; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; +use Symfony\Component\Security\Core\Role\Role; + class ChillExportVoter extends Voter { - const EXPORT = 'chill_export'; - + public const EXPORT = 'chill_export'; + /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + public function __construct(AuthorizationHelper $authorizationHelper) { $this->authorizationHelper = $authorizationHelper; } - + protected function supports($attribute, $subject): bool { - return $attribute === self::EXPORT; + return self::EXPORT === $attribute; } protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool @@ -53,10 +38,10 @@ class ChillExportVoter extends Voter if (!$token->getUser() instanceof User) { return false; } - + $centers = $this->authorizationHelper ->getReachableCenters($token->getUser(), new Role($attribute)); - + return count($centers) > 0; } } diff --git a/src/Bundle/ChillMainBundle/Security/Authorization/ChillVoterInterface.php b/src/Bundle/ChillMainBundle/Security/Authorization/ChillVoterInterface.php index 3e89d2595..2cfdc18ae 100644 --- a/src/Bundle/ChillMainBundle/Security/Authorization/ChillVoterInterface.php +++ b/src/Bundle/ChillMainBundle/Security/Authorization/ChillVoterInterface.php @@ -1,30 +1,17 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Security\Authorization; /** * Provides methods for compiling voter and build admin role fields. - * - * @author Julien Fastré */ interface ChillVoterInterface { - } diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php index e9809d431..7f5f44777 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEvent.php @@ -1,77 +1,73 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Security\PasswordRecover; use Chill\MainBundle\Entity\User; use Symfony\Component\EventDispatcher\Event; -/** - * - * - * @author Julien Fastré - */ class PasswordRecoverEvent extends Event { + public const ASK_TOKEN_INVALID_FORM = 'chill_main.ask_token_invalid_form'; + + public const ASK_TOKEN_SUCCESS = 'chill_main.ask_token_success'; + + public const INVALID_TOKEN = 'chill_main.password_recover_invalid_token'; + /** - * - * @var User - */ - protected $user; - - /** - * - * @var string - */ - protected $token; - - /** - * * @var string */ protected $ip; - + /** - * - * @var boolean + * @var bool */ protected $safelyGenerated; - - const ASK_TOKEN_INVALID_FORM = 'chill_main.ask_token_invalid_form'; - const INVALID_TOKEN = 'chill_main.password_recover_invalid_token'; - const ASK_TOKEN_SUCCESS = 'chill_main.ask_token_success'; - + + /** + * @var string + */ + protected $token; + + /** + * @var User + */ + protected $user; + /** - * * @param type $token * @param User $user * @param type $ip * @param bool $safelyGenerated true if generated safely (from console command, etc.) */ - public function __construct($token = null, User $user = null, $ip = null, bool $safelyGenerated = false) + public function __construct($token = null, ?User $user = null, $ip = null, bool $safelyGenerated = false) { $this->user = $user; $this->token = $token; $this->ip = $ip; $this->safelyGenerated = $safelyGenerated; } - + + public function getIp() + { + return $this->ip; + } + + /** + * @return string + */ + public function getToken() + { + return $this->token; + } + /** - * * @return User|null */ public function getUser() @@ -79,38 +75,16 @@ class PasswordRecoverEvent extends Event return $this->user; } - /** - * - * @return string - */ - public function getToken() - { - return $this->token; - } - - public function getIp() - { - return $this->ip; - } - - /** - * - * @return boolean - */ public function hasIp(): bool { return !empty($this->ip); } - - /** - * - * @return boolean - */ + public function hasUser(): bool { return $this->user instanceof User; } - + public function isSafelyGenerated(): bool { return $this->safelyGenerated; diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEventSubscriber.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEventSubscriber.php index 686a0dec5..eec173582 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEventSubscriber.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverEventSubscriber.php @@ -1,83 +1,67 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Security\PasswordRecover; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -/** - * - * - * @author Julien Fastré - */ class PasswordRecoverEventSubscriber implements EventSubscriberInterface { /** - * * @var PasswordRecoverLocker */ protected $locker; - + public function __construct(PasswordRecoverLocker $locker) { $this->locker = $locker; } - public static function getSubscribedEvents(): array { return [ PasswordRecoverEvent::INVALID_TOKEN => [ - [ 'onInvalidToken' ] + ['onInvalidToken'], ], PasswordRecoverEvent::ASK_TOKEN_INVALID_FORM => [ - [ 'onAskTokenInvalidForm' ] + ['onAskTokenInvalidForm'], ], PasswordRecoverEvent::ASK_TOKEN_SUCCESS => [ - [ 'onAskTokenSuccess'] - ] + ['onAskTokenSuccess'], + ], ]; } - - public function onInvalidToken(PasswordRecoverEvent $event) - { - // set global lock - $this->locker->createLock('invalid_token_global', null); - - // set ip lock - if ($event->hasIp()) { - $this->locker->createLock('invalid_token_by_ip', $event->getIp()); - } - } - + public function onAskTokenInvalidForm(PasswordRecoverEvent $event) { // set global lock $this->locker->createLock('ask_token_invalid_form_global', null); - + // set ip lock if ($event->hasIp()) { $this->locker->createLock('ask_token_invalid_form_by_ip', $event->getIp()); } } - + public function onAskTokenSuccess(PasswordRecoverEvent $event) { $this->locker->createLock('ask_token_success_by_user', $event->getUser()); } + + public function onInvalidToken(PasswordRecoverEvent $event) + { + // set global lock + $this->locker->createLock('invalid_token_global', null); + + // set ip lock + if ($event->hasIp()) { + $this->locker->createLock('invalid_token_by_ip', $event->getIp()); + } + } } diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverLocker.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverLocker.php index 95c3890d0..7e6b50ad0 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverLocker.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverLocker.php @@ -1,170 +1,163 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Security\PasswordRecover; use Chill\MainBundle\Redis\ChillRedis; +use LogicException; use Psr\Log\LoggerInterface; +use UnexpectedValueException; -/** - * - * - * @author Julien Fastré - */ class PasswordRecoverLocker { - + public const ASK_TOKEN_INVALID_FORM_TTL = 3600; + /** - * The maximum of invalid token globally (across all ip) + * TTL to keep invalid token recorded. */ - const MAX_INVALID_TOKEN_GLOBAL = 50; - + public const INVALID_TOKEN_TTL = 3600; + + public const MAX_ASK_TOKEN_BY_USER = 10; + + public const MAX_ASK_TOKEN_INVALID_FORM_BY_IP = 10; + + public const MAX_ASK_TOKEN_INVALID_FORM_GLOBAL = 50; + /** - * The maximum of invalid token by ip + * The maximum of invalid token by ip. */ - const MAX_INVALID_TOKEN_BY_IP = 10; - + public const MAX_INVALID_TOKEN_BY_IP = 10; + /** - * TTL to keep invalid token recorded + * The maximum of invalid token globally (across all ip). */ - const INVALID_TOKEN_TTL = 3600; - - const MAX_ASK_TOKEN_INVALID_FORM_GLOBAL = 50; - - const MAX_ASK_TOKEN_INVALID_FORM_BY_IP = 10; - - const MAX_ASK_TOKEN_BY_USER = 10; - - const ASK_TOKEN_INVALID_FORM_TTL = 3600; - + public const MAX_INVALID_TOKEN_GLOBAL = 50; + /** - * * @var ChillRedis */ protected $chillRedis; - + /** - * * @var LoggerInterface */ protected $logger; - + public function __construct(ChillRedis $chillRedis, LoggerInterface $logger) { $this->chillRedis = $chillRedis; $this->logger = $logger; } - public function createLock($usage, $discriminator = null) { $max = $this->getMax($usage); $ttl = $this->getTtl($usage); - - for ($i = 0; $i < $max; $i++) { + + for ($i = 0; $i < $max; ++$i) { $key = self::generateLockKey($usage, $i, $discriminator); - + if (0 === $this->chillRedis->exists($key)) { $this->chillRedis->set($key, 1); $this->chillRedis->setTimeout($key, $ttl); - + break; } } } - - public function isLocked($usage, $discriminator = null) - { - $max = $this->getMax($usage); - - for ($i = 0; $i < $max; $i++) { - $key = self::generateLockKey($usage, $i, $discriminator); - if ($this->chillRedis->exists($key) === 0) { - return false; - } + /** + * @param string $usage 'invalid_token_global' or ... + * @param mixed|null $discriminator + */ + public static function generateLockKey($usage, int $number, $discriminator = null) + { + switch ($usage) { + case 'invalid_token_global': + return sprintf('invalid_token_global_%d', $number); + + case 'invalid_token_by_ip': + return sprintf('invalid_token_ip_%s_%d', $discriminator, $number); + + case 'ask_token_invalid_form_global': + return sprintf('ask_token_invalid_form_global_%d', $number); + + case 'ask_token_invalid_form_by_ip': + return sprintf('ask_token_invalid_form_by_ip_%s_%d', $discriminator, $number); + + case 'ask_token_success_by_user': + return sprintf('ask_token_success_by_user_%s_%d', $discriminator->getId(), $number); + + default: + throw new LogicException('this usage is not implemented'); } - - $this->logger->warning("locking reaching for password recovery", [ - 'usage' => $usage, - 'discriminator' => $discriminator - ]); - - return true; } - + public function getMax($usage) { switch ($usage) { case 'invalid_token_global': return self::MAX_INVALID_TOKEN_GLOBAL; + case 'invalid_token_by_ip': return self::MAX_INVALID_TOKEN_BY_IP; + case 'ask_token_invalid_form_global': return self::MAX_ASK_TOKEN_INVALID_FORM_GLOBAL; + case 'ask_token_invalid_form_by_ip': return self::MAX_ASK_TOKEN_INVALID_FORM_BY_IP; + case 'ask_token_success_by_user': return self::MAX_ASK_TOKEN_BY_USER; - + default: - throw new \UnexpectedValueException("this usage '$usage' is not yet implemented"); + throw new UnexpectedValueException("this usage '{$usage}' is not yet implemented"); } } - + public function getTtl($usage) { switch ($usage) { case 'invalid_token_global': case 'invalid_token_by_ip': return self::INVALID_TOKEN_TTL; - + case 'ask_token_invalid_form_global': case 'ask_token_invalid_form_by_ip': return self::ASK_TOKEN_INVALID_FORM_TTL; - + case 'ask_token_success_by_user': return self::ASK_TOKEN_INVALID_FORM_TTL * 24; - + default: - throw new \UnexpectedValueException("this usage '$usage' is not yet implemented"); + throw new UnexpectedValueException("this usage '{$usage}' is not yet implemented"); } } - - /** - * - * @param string $usage 'invalid_token_global' or ... - * @param int $number - */ - public static function generateLockKey($usage, int $number, $discriminator = null) + + public function isLocked($usage, $discriminator = null) { - switch($usage) { - case "invalid_token_global": - return sprintf('invalid_token_global_%d', $number); - case "invalid_token_by_ip": - return sprintf('invalid_token_ip_%s_%d', $discriminator, $number); - case "ask_token_invalid_form_global": - return sprintf('ask_token_invalid_form_global_%d', $number); - case "ask_token_invalid_form_by_ip": - return sprintf('ask_token_invalid_form_by_ip_%s_%d', $discriminator, $number); - case 'ask_token_success_by_user': - return sprintf('ask_token_success_by_user_%s_%d', $discriminator->getId(), $number); - default: - throw new \LogicException("this usage is not implemented"); + $max = $this->getMax($usage); + + for ($i = 0; $i < $max; ++$i) { + $key = self::generateLockKey($usage, $i, $discriminator); + + if ($this->chillRedis->exists($key) === 0) { + return false; + } } + + $this->logger->warning('locking reaching for password recovery', [ + 'usage' => $usage, + 'discriminator' => $discriminator, + ]); + + return true; } } diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverVoter.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverVoter.php index 324f76b02..26a3cb116 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverVoter.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/PasswordRecoverVoter.php @@ -1,67 +1,52 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Security\PasswordRecover; - -use Symfony\Component\Security\Core\Authorization\Voter\Voter; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\HttpFoundation\RequestStack; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Security\PasswordRecover; + +use Chill\MainBundle\Entity\User; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\Voter\Voter; + class PasswordRecoverVoter extends Voter { - const TRY_TOKEN = 'CHILL_PASSWORD_TRY_TOKEN'; - const ASK_TOKEN = 'CHILL_PASSWORD_ASK_TOKEN'; - - protected $supported = [ - self::TRY_TOKEN, - self::ASK_TOKEN - ]; - + public const ASK_TOKEN = 'CHILL_PASSWORD_ASK_TOKEN'; + + public const TRY_TOKEN = 'CHILL_PASSWORD_TRY_TOKEN'; + /** - * * @var PasswordRecoverLocker */ protected $locker; - + /** - * * @var RequestStack */ protected $requestStack; - + + protected $supported = [ + self::TRY_TOKEN, + self::ASK_TOKEN, + ]; + public function __construct(PasswordRecoverLocker $locker, RequestStack $requestStack) { $this->locker = $locker; $this->requestStack = $requestStack; } - protected function supports($attribute, $subject): bool { if (!in_array($attribute, $this->supported)) { return false; } - + return true; } @@ -69,34 +54,36 @@ class PasswordRecoverVoter extends Voter { switch ($attribute) { case self::TRY_TOKEN: - if (TRUE === $this->locker->isLocked('invalid_token_global')) { + if (true === $this->locker->isLocked('invalid_token_global')) { return false; } - + $ip = $this->requestStack->getCurrentRequest()->getClientIp(); - if (TRUE === $this->locker->isLocked('invalid_token_by_ip', $ip)) { + + if (true === $this->locker->isLocked('invalid_token_by_ip', $ip)) { return false; } - + return true; + case self::ASK_TOKEN: - if (TRUE === $this->locker->isLocked('ask_token_invalid_form_global')) { + if (true === $this->locker->isLocked('ask_token_invalid_form_global')) { return false; } - + $ip = $this->requestStack->getCurrentRequest()->getClientIp(); - if (TRUE === $this->locker->isLocked('ask_token_invalid_form_by_ip', $ip)) { + + if (true === $this->locker->isLocked('ask_token_invalid_form_by_ip', $ip)) { return false; } - + if ($subject instanceof User) { - if (TRUE === $this->locker->isLocked('ask_token_success_by_user', $subject)) { + if (true === $this->locker->isLocked('ask_token_success_by_user', $subject)) { return false; } } - + return true; - } } } diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php index 969f774a6..a841c4df4 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/RecoverPasswordHelper.php @@ -1,59 +1,45 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Security\PasswordRecover; - -use Chill\MainBundle\Security\PasswordRecover\TokenManager; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Chill\MainBundle\Notification\Mailer; -use Chill\MainBundle\Entity\User; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Security\PasswordRecover; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Notification\Mailer; +use DateTimeInterface; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; + +use function array_merge; + class RecoverPasswordHelper { + public const RECOVER_PASSWORD_ROUTE = 'password_recover'; + /** - * - * @var TokenManager - */ - protected $tokenManager; - - /** - * - * @var UrlGeneratorInterface - */ - protected $urlGenerator; - - /** - * * @var Mailer */ protected $mailer; - + protected $routeParameters; - - const RECOVER_PASSWORD_ROUTE = 'password_recover'; - + + /** + * @var TokenManager + */ + protected $tokenManager; + + /** + * @var UrlGeneratorInterface + */ + protected $urlGenerator; + public function __construct( - TokenManager $tokenManager, - UrlGeneratorInterface $urlGenerator, + TokenManager $tokenManager, + UrlGeneratorInterface $urlGenerator, Mailer $mailer, array $routeParameters ) { @@ -64,64 +50,65 @@ class RecoverPasswordHelper } /** - * - * @param User $user - * @param \DateTimeInterface $expiration * @param bool $absolute * @param array $parameters additional parameters to url + * * @return string */ - public function generateUrl(User $user, \DateTimeInterface $expiration, $absolute = true, array $parameters = []) + public function generateUrl(User $user, DateTimeInterface $expiration, $absolute = true, array $parameters = []) { - $context = $this->urlGenerator->getContext(); $previousHost = $context->getHost(); $previousScheme = $context->getScheme(); - + $context->setHost($this->routeParameters['host']); $context->setScheme($this->routeParameters['scheme']); - + $url = $this->urlGenerator->generate( - self::RECOVER_PASSWORD_ROUTE, - \array_merge( + self::RECOVER_PASSWORD_ROUTE, + array_merge( $this->tokenManager->generate($user, $expiration), - $parameters), + $parameters + ), $absolute ? UrlGeneratorInterface::ABSOLUTE_URL : UrlGeneratorInterface::ABSOLUTE_PATH - ); - + ); + // reset the host $context->setHost($previousHost); $context->setScheme($previousScheme); - + return $url; } - + public function sendRecoverEmail( - User $user, - \DateTimeInterface $expiration, - $template = '@ChillMain/Password/recover_email.txt.twig', - array $templateParameters = [], + User $user, + DateTimeInterface $expiration, + $template = '@ChillMain/Password/recover_email.txt.twig', + array $templateParameters = [], $force = false, array $additionalUrlParameters = [], $emailSubject = 'Recover your password' ) { $content = $this->mailer->renderContentToUser( - $user, - $template, - \array_merge([ + $user, + $template, + array_merge( + [ 'user' => $user, - 'url' => $this->generateUrl($user, $expiration, true, $additionalUrlParameters) + 'url' => $this->generateUrl($user, $expiration, true, $additionalUrlParameters), ], $templateParameters - )); - + ) + ); + $this->mailer->sendNotification( - $user, - [ $emailSubject ], + $user, + [$emailSubject], [ 'text/plain' => $content, - ], - null, - $force); + ], + null, + $force + ); } } diff --git a/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php b/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php index 3dc0c1060..8f590e6a7 100644 --- a/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php +++ b/src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php @@ -1,103 +1,100 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Security\PasswordRecover; use Chill\MainBundle\Entity\User; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use Psr\Log\LoggerInterface; +use UnexpectedValueException; + +use function bin2hex; +use function hash; +use function hex2bin; +use function random_bytes; +use function strlen; +use function trim; -/** - * - * - * @author Julien Fastré - */ class TokenManager { + public const HASH = 'h'; + + public const TIMESTAMP = 'ts'; + + public const TOKEN = 't'; + + public const TOKEN_LENGTH = 24; + + public const USERNAME_CANONICAL = 'u'; + /** - * - * @var string - */ - protected $secret; - - /** - * * @var LoggerInterface */ protected $logger; - - const TOKEN = 't'; - const HASH = 'h'; - const TIMESTAMP = 'ts'; - const USERNAME_CANONICAL = 'u'; - - const TOKEN_LENGTH = 24; - + + /** + * @var string + */ + protected $secret; + public function __construct($secret, LoggerInterface $logger) { $this->secret = $secret; $this->logger = $logger; } - - public function generate(User $user, \DateTimeInterface $expiration) + + public function generate(User $user, DateTimeInterface $expiration) { - $token = \random_bytes(self::TOKEN_LENGTH); + $token = random_bytes(self::TOKEN_LENGTH); $username = $user->getUsernameCanonical(); - + if (empty($username)) { - throw new \UnexpectedValueException("username should not be empty to generate a token"); + throw new UnexpectedValueException('username should not be empty to generate a token'); } - + $timestamp = $expiration->getTimestamp(); - $hash = \hash('sha1', $token.$username.$timestamp.$this->secret); - - return [ - self::HASH => $hash, - self::TOKEN => \bin2hex($token), - self::TIMESTAMP => $timestamp, - self::USERNAME_CANONICAL => $username - ]; + $hash = hash('sha1', $token . $username . $timestamp . $this->secret); + + return [ + self::HASH => $hash, + self::TOKEN => bin2hex($token), + self::TIMESTAMP => $timestamp, + self::USERNAME_CANONICAL => $username, + ]; } - + public function verify($hash, $token, User $user, $timestamp) { - $token = \hex2bin(\trim($token)); - - if (\strlen($token) !== self::TOKEN_LENGTH) { + $token = hex2bin(trim($token)); + + if (strlen($token) !== self::TOKEN_LENGTH) { return false; } - + $username = $user->getUsernameCanonical(); - $date = \DateTimeImmutable::createFromFormat('U', $timestamp); - - if ($date < new \DateTime('now')) { - + $date = DateTimeImmutable::createFromFormat('U', $timestamp); + + if ($date < new DateTime('now')) { $this->logger->info('receiving a password recover token with expired ' . 'validity'); - + return false; } - - $expected = \hash('sha1', $token.$username.$timestamp.$this->secret); - + + $expected = hash('sha1', $token . $username . $timestamp . $this->secret); + if ($expected !== $hash) { return false; } - + return true; } - } diff --git a/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php b/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php index d5f49db5d..fa8361ba5 100644 --- a/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php +++ b/src/Bundle/ChillMainBundle/Security/ProvideRoleHierarchyInterface.php @@ -1,41 +1,31 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Security; /** - * Give a hierarchy for the role. - * - * This hierarchy allow to sort roles, which is useful in UI + * Give a hierarchy for the role. * - * @author Julien Fastré + * This hierarchy allow to sort roles, which is useful in UI */ interface ProvideRoleHierarchyInterface extends ProvideRoleInterface { /** * Return an array of roles, where keys are the hierarchy, and values * an array of roles. - * - * Example: - * + * + * Example: + * * ``` * [ 'Title' => [ 'CHILL_FOO_SEE', 'CHILL_FOO_UPDATE' ] ] * ``` - * + * * @return array where keys are the hierarchy, and values an array of roles: `[ 'title' => [ 'CHILL_FOO_SEE', 'CHILL_FOO_UPDATE' ] ]` */ public function getRolesWithHierarchy(); diff --git a/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php b/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php index 08a48181a..dcf026c44 100644 --- a/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php +++ b/src/Bundle/ChillMainBundle/Security/ProvideRoleInterface.php @@ -1,52 +1,40 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Security; /** - * Declare role - * + * Declare role. + * * The role are added to the configuration at compile time. - * - * The implemented object must be declared as a service and tagged as - * + * + * The implemented object must be declared as a service and tagged as + * *
  * my_role_declaration:
  *    # ...
  *    tags:
  *       - { name: chill.role }
  * 
- * - * @author Julien Fastré */ interface ProvideRoleInterface { /** - * return an array of role provided by the object - * + * return an array of role provided by the object. + * * @return string[] array of roles (as string) */ public function getRoles(); - + /** - * return roles which doesn't need - * + * return roles which doesn't need. + * * @return string[] array of roles without scopes */ public function getRolesWithoutScope(); diff --git a/src/Bundle/ChillMainBundle/Security/RoleProvider.php b/src/Bundle/ChillMainBundle/Security/RoleProvider.php index f72435cb1..446c6d9f4 100644 --- a/src/Bundle/ChillMainBundle/Security/RoleProvider.php +++ b/src/Bundle/ChillMainBundle/Security/RoleProvider.php @@ -1,136 +1,123 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Security; -/** - * - * - * @author Julien Fastré - */ +use function array_fill_keys; +use function array_key_exists; + class RoleProvider { /** - * * @var ProvideRoleInterface[] */ - private $providers = array(); - + private $providers = []; + /** * an array where keys are the role, and value is the title * for the given role. - * + * * Null when not initialized. * * @var array|null */ - private $rolesTitlesCache = null; - + private $rolesTitlesCache; + /** - * Add a role provider - * + * Add a role provider. + * * @internal This function is called by the dependency injector: it inject provider + * * @param \Chill\MainBundle\Security\ProvideRoleInterface $provider */ - public function addProvider(ProvideRoleInterface $provider) + public function addProvider(ProvideRoleInterface $provider) { $this->providers[] = $provider; } - + /** - * * @return string[] the roles as string */ public function getRoles() { - $roles = array(); + $roles = []; + foreach ($this->providers as $provider) { - if ($provider->getRoles() !== NULL) { + if ($provider->getRoles() !== null) { $roles = array_merge($roles, $provider->getRoles()); } } - + return $roles; } - + /** - * * @return string[] the roles as string */ public function getRolesWithoutScopes() { - $roles = array(); + $roles = []; + foreach ($this->providers as $provider) { - if ($provider->getRolesWithoutScope() !== NULL) { + if ($provider->getRolesWithoutScope() !== null) { $roles = array_merge($roles, $provider->getRolesWithoutScope()); } } - + return $roles; } - + /** - * initialize the array for caching role and titles - * + * Get the title for each role. + * + * @param string $role + * + * @return string the title of the role + */ + public function getRoleTitle($role) + { + $this->initializeRolesTitlesCache(); + + if (!array_key_exists($role, $this->rolesTitlesCache)) { + // this case might happens when the role is not described in + // `getRolesWithHierarchy` + return null; + } + + return $this->rolesTitlesCache[$role]; + } + + /** + * initialize the array for caching role and titles. */ private function initializeRolesTitlesCache() { // break if already initialized - if ($this->rolesTitlesCache !== null) { + if (null !== $this->rolesTitlesCache) { return; } - + foreach ($this->providers as $provider) { if ($provider instanceof ProvideRoleHierarchyInterface) { foreach ($provider->getRolesWithHierarchy() as $title => $roles) { - foreach($roles as $role) { + foreach ($roles as $role) { $this->rolesTitlesCache[$role] = $title; } } } else { if ($provider->getRoles() !== null) { $this->rolesTitlesCache = \array_merge( - $this->rolesTitlesCache, - \array_fill_keys($provider->getRoles(), null) - ); + $this->rolesTitlesCache, + array_fill_keys($provider->getRoles(), null) + ); } } } } - - /** - * Get the title for each role. - * - * @param string $role - * @return string the title of the role - */ - public function getRoleTitle($role) - { - $this->initializeRolesTitlesCache(); - - if (! \array_key_exists($role, $this->rolesTitlesCache)) { - // this case might happens when the role is not described in - // `getRolesWithHierarchy` - return null; - } - - return $this->rolesTitlesCache[$role]; - } - } diff --git a/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php b/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php index b741fd2c2..a3ac59033 100644 --- a/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php +++ b/src/Bundle/ChillMainBundle/Security/UserProvider/UserProvider.php @@ -1,83 +1,69 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Security\UserProvider; - -use Symfony\Component\Security\Core\User\UserProviderInterface; -use Symfony\Component\Security\Core\User\UserInterface; -use Doctrine\ORM\EntityManagerInterface; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; -use Symfony\Component\Security\Core\Exception\UnsupportedUserException; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Security\UserProvider; + +use Chill\MainBundle\Entity\User; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Exception\UnsupportedUserException; +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; + class UserProvider implements UserProviderInterface { /** - * * @var EntityManagerInterface */ protected $em; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - public function loadUserByUsername($username): UserInterface { try { $user = $this->em->createQuery(sprintf( - "SELECT u FROM %s u " - . "WHERE u.usernameCanonical = UNACCENT(LOWER(:pattern)) " - . "OR " - . "u.emailCanonical = UNACCENT(LOWER(:pattern))", - User::class)) + 'SELECT u FROM %s u ' + . 'WHERE u.usernameCanonical = UNACCENT(LOWER(:pattern)) ' + . 'OR ' + . 'u.emailCanonical = UNACCENT(LOWER(:pattern))', + User::class + )) ->setParameter('pattern', $username) ->getSingleResult(); } catch (\Doctrine\ORM\NoResultException $e) { throw new UsernameNotFoundException(sprintf('Bad credentials.', $username)); } - + return $user; } public function refreshUser(UserInterface $user): UserInterface { if (!$user instanceof User) { - throw new UnsupportedUserException("Unsupported user class: cannot reload this user"); + throw new UnsupportedUserException('Unsupported user class: cannot reload this user'); } - + $reloadedUser = $this->em->getRepository(User::class)->find($user->getId()); - - if (NULL === $reloadedUser) { + + if (null === $reloadedUser) { throw new UsernameNotFoundException(sprintf('User with ID "%s" could not be reloaded.', $user->getId())); } - + return $reloadedUser; } public function supportsClass($class): bool { - return $class === User::class; + return User::class === $class; } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Model/Collection.php b/src/Bundle/ChillMainBundle/Serializer/Model/Collection.php index 9983d3595..420520b66 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Model/Collection.php +++ b/src/Bundle/ChillMainBundle/Serializer/Model/Collection.php @@ -1,28 +1,35 @@ items = $items; $this->paginator = $paginator; } - public function getPaginator(): PaginatorInterface - { - return $this->paginator; - } - public function getItems() { return $this->items; } + + public function getPaginator(): PaginatorInterface + { + return $this->paginator; + } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php index 26182d936..bfcef8213 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CenterNormalizer.php @@ -1,20 +1,10 @@ - * - * 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 . + +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Serializer\Normalizer; @@ -22,22 +12,18 @@ namespace Chill\MainBundle\Serializer\Normalizer; use Chill\MainBundle\Entity\Center; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -/** - * - * - */ class CenterNormalizer implements NormalizerInterface { - public function normalize($center, string $format = null, array $context = array()) + public function normalize($center, ?string $format = null, array $context = []) { /** @var Center $center */ return [ 'id' => $center->getId(), - 'name' => $center->getName() + 'name' => $center->getName(), ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { return $data instanceof Center; } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php index 1ba95d924..a69ac20ce 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/CollectionNormalizer.php @@ -1,31 +1,33 @@ getPaginator(); $data['count'] = $paginator->getTotalItems(); $pagination['first'] = $paginator->getCurrentPageFirstItemNumber(); $pagination['items_per_page'] = $paginator->getItemsPerPage(); - $pagination['next'] = $paginator->hasNextPage() ? + $pagination['next'] = $paginator->hasNextPage() ? $paginator->getNextPage()->generateUrl() : null; $pagination['previous'] = $paginator->hasPreviousPage() ? $paginator->getPreviousPage()->generateUrl() : null; @@ -33,9 +35,17 @@ class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterf $data['pagination'] = $pagination; // normalize results - $data['results'] = $this->normalizer->normalize($collection->getItems(), - $format, $context); + $data['results'] = $this->normalizer->normalize( + $collection->getItems(), + $format, + $context + ); return $data; } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof Collection; + } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php index fd902b184..8b40f746c 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php @@ -1,39 +1,30 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Serializer\Normalizer; +use DateTimeInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class DateNormalizer implements NormalizerInterface { - public function normalize($date, string $format = null, array $context = array()) + public function normalize($date, ?string $format = null, array $context = []) { - /** @var \DateTimeInterface $date */ + /** @var DateTimeInterface $date */ return [ - 'datetime' => $date->format(\DateTimeInterface::ISO8601), - 'u' => $date->getTimestamp() + 'datetime' => $date->format(DateTimeInterface::ISO8601), + 'u' => $date->getTimestamp(), ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { - return $data instanceof \DateTimeInterface; + return $data instanceof DateTimeInterface; } } diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php index 2a71de52b..ca505c30e 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php @@ -1,20 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Serializer\Normalizer; @@ -22,22 +12,18 @@ namespace Chill\MainBundle\Serializer\Normalizer; use Chill\MainBundle\Entity\User; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -/** - * - * - */ class UserNormalizer implements NormalizerInterface { - public function normalize($user, string $format = null, array $context = array()) + public function normalize($user, ?string $format = null, array $context = []) { /** @var User $user */ return [ 'id' => $user->getId(), - 'username' => $user->getUsername() + 'username' => $user->getUsername(), ]; } - public function supportsNormalization($data, string $format = null): bool + public function supportsNormalization($data, ?string $format = null): bool { return $data instanceof User; } diff --git a/src/Bundle/ChillMainBundle/Templating/CSVCellTwig.php b/src/Bundle/ChillMainBundle/Templating/CSVCellTwig.php index f587b41fe..1820d1775 100644 --- a/src/Bundle/ChillMainBundle/Templating/CSVCellTwig.php +++ b/src/Bundle/ChillMainBundle/Templating/CSVCellTwig.php @@ -1,23 +1,10 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Templating; @@ -28,30 +15,14 @@ use Twig\TwigFilter; /** * Twig filter to transform a string in a safer way to be the content of a csv * cell. - * + * * This filter replace the char " by "" */ class CSVCellTwig extends AbstractExtension { - /* - * Returns a list of filters to add to the existing list. - * - * (non-PHPdoc) - * @see Twig_Extension::getFilters() - */ - public function getFilters() - { - return array( - new TwigFilter( - 'csv_cell', - array($this, 'csvCellFilter'), - array('is_safe' => array('html'))) - ); - } - /* * Replace into a string the char " by "" - * + * * @param String $content The input string. * @return String The safe string. */ @@ -59,7 +30,24 @@ class CSVCellTwig extends AbstractExtension { return str_replace('"', '""', $content); } - + + /* + * Returns a list of filters to add to the existing list. + * + * (non-PHPdoc) + * @see Twig_Extension::getFilters() + */ + public function getFilters() + { + return [ + new TwigFilter( + 'csv_cell', + [$this, 'csvCellFilter'], + ['is_safe' => ['html']] + ), + ]; + } + /* * Returns the name of the extension. * diff --git a/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php b/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php index 4db950e6c..de49d7ff8 100644 --- a/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php +++ b/src/Bundle/ChillMainBundle/Templating/ChillMarkdownRenderExtension.php @@ -1,29 +1,20 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating; +use Parsedown; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; -use Parsedown; - /** - * Render markdown + * Render markdown. */ final class ChillMarkdownRenderExtension extends AbstractExtension { @@ -31,22 +22,22 @@ final class ChillMarkdownRenderExtension extends AbstractExtension * @var Parsedown */ protected $parsedown; - + public function __construct() { $this->parsedown = new Parsedown(); $this->parsedown->setSafeMode(true); } - + public function getFilters(): array { return [ new TwigFilter('chill_markdown_to_html', [$this, 'renderMarkdownToHtml'], [ - 'is_safe' => [ 'html' ] - ]) + 'is_safe' => ['html'], + ]), ]; } - + public function renderMarkdownToHtml(string $var): string { return $this->parsedown->parse($var); diff --git a/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php b/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php index b6b267386..19bf3ce6e 100644 --- a/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/ChillTwigHelper.php @@ -1,32 +1,21 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Templating; - -use Twig\Extension\AbstractExtension; -use Twig\TwigFilter; -use Twig\Environment; /** - * + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Templating; + +use DateTimeInterface; +use Twig\Environment; +use Twig\Extension\AbstractExtension; +use Twig\TwigFilter; + +use function array_merge; + class ChillTwigHelper extends AbstractExtension { public function getFilters() @@ -34,51 +23,53 @@ class ChillTwigHelper extends AbstractExtension return [ new TwigFilter('chill_print_or_message', [$this, 'printOrMessage'], [ 'needs_environment' => true, - 'is_safe' => ['html', 'html_attrs'] + 'is_safe' => ['html', 'html_attrs'], ]), ]; } - + /** - * Print `value` inside a template, or, if $value is empty, + * Print `value` inside a template, or, if $value is empty, * print $message. - * + * * The template can be customized. The template is a full path to another - * template, or one of the key belows: - * + * template, or one of the key belows: + * * - 'default' ; * - 'blockquote' ; - * + * * `DateTimeInterface are also rendered. The date and time format may be set * using those key in `$options´ parameter: - * + * * - `date_format` (default to `'medium'`) * - `time_format` (default to `'none'`) - * - * @param Environment $twig + * * @param string $value Default to 'No value'. Fallback to default if null * @param string $message * @param string $template - * @param array $options + * * @return string */ public function printOrMessage( Environment $twig, - $value, - $message = 'No value', + $value, + $message = 'No value', $template = 'default', array $options = [] ) { - if ($value instanceof \DateTimeInterface) { - $options = \array_merge([ + if ($value instanceof DateTimeInterface) { + $options = array_merge([ 'date_format' => 'medium', - 'time_format' => 'none' + 'time_format' => 'none', ], $options); + switch ($template) { case 'default': case 'blockquote': - $t = '@ChillMain/Extensions/PrintOrMessage/'.$template.'_date.html.twig'; + $t = '@ChillMain/Extensions/PrintOrMessage/' . $template . '_date.html.twig'; + break; + default: $t = $template; } @@ -86,16 +77,18 @@ class ChillTwigHelper extends AbstractExtension switch ($template) { case 'default': case 'blockquote': - $t = '@ChillMain/Extensions/PrintOrMessage/'.$template.'.html.twig'; + $t = '@ChillMain/Extensions/PrintOrMessage/' . $template . '.html.twig'; + break; + default: $t = $template; } } - - return $twig->render($t, \array_merge([ + + return $twig->render($t, array_merge([ 'value' => $value, - 'message' => $message ?? 'No value' + 'message' => $message ?? 'No value', ], $options)); } } diff --git a/src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php b/src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php index c3f0f0688..fa65369c4 100644 --- a/src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/ChillTwigRoutingHelper.php @@ -1,152 +1,139 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating; +use Symfony\Bridge\Twig\Extension\RoutingExtension; +use Symfony\Component\HttpFoundation\RequestStack; use Twig\Extension\AbstractExtension; use Twig\Node\Node; -use Twig\TwigFunction; use Twig\TwigFilter; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Bridge\Twig\Extension\RoutingExtension; +use Twig\TwigFunction; /** * Provides function to build path with returnPath. - * - * The logic of the function is based on the original routing extension. * + * The logic of the function is based on the original routing extension. */ class ChillTwigRoutingHelper extends AbstractExtension { /** - * - * @var RequestStack - */ - protected $requestStack; - - /** - * * @var RoutingExtension */ protected $originalExtension; - + + /** + * @var RequestStack + */ + protected $requestStack; + public function __construct( - RequestStack $requestStack, + RequestStack $requestStack, RoutingExtension $originalExtension ) { $this->requestStack = $requestStack; $this->originalExtension = $originalExtension; } - - public function getFunctions() - { - return [ - new TwigFunction('chill_return_path_or', [$this, 'getReturnPathOr'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ), - new TwigFunction('chill_path_add_return_path', [$this, 'getPathAddReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ), - new TwigFunction('chill_path_forward_return_path', [$this, 'getPathForwardReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']] ), - - ]; - } - public function getFilters() { return [ new TwigFilter('chill_return_path_label', [$this, 'getLabelReturnPath']), ]; } - - public function isUrlGenerationSafe(Node $argsNode) + + public function getFunctions() { - return $this->originalExtension->isUrlGenerationSafe($argsNode); + return [ + new TwigFunction('chill_return_path_or', [$this, 'getReturnPathOr'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]), + new TwigFunction('chill_path_add_return_path', [$this, 'getPathAddReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]), + new TwigFunction('chill_path_forward_return_path', [$this, 'getPathForwardReturnPath'], ['is_safe_callback' => [$this, 'isUrlGenerationSafe']]), + ]; } - + public function getLabelReturnPath($default) { $request = $this->requestStack->getCurrentRequest(); - + return $request->query->get('returnPathLabel', null) ?? $default; } - + /** - * Return the return path if it exists, or generate the path if not. - * - * @param string $name - * @param array $parameters - * @param bool $relative - * @return string - */ - public function getReturnPathOr($name, $parameters = [], $relative = false) - { - $request = $this->requestStack->getCurrentRequest(); - - if ($request->query->has('returnPath')) { - return $request->query->get('returnPath'); - } - - return $this->originalExtension->getPath($name, $parameters, $relative); - } - - /** - * Build an url with a returnPath parameter to current page - * + * Build an url with a returnPath parameter to current page. + * * @param string $name * @param array $parameters * @param bool $relative + * @param mixed|null $label + * * @return string */ public function getPathAddReturnPath($name, $parameters = [], $relative = false, $label = null) { $request = $this->requestStack->getCurrentRequest(); - + $parameters['returnPath'] = $request->getRequestUri(); - + if ($label) { $parameters['returnPathLabel'] = $label; } - + return $this->originalExtension->getPath($name, $parameters, $relative); } - + /** - * Build an url with a returnPath parameter to current page - * + * Build an url with a returnPath parameter to current page. + * * @param string $name * @param array $parameters * @param bool $relative + * * @return string */ public function getPathForwardReturnPath($name, $parameters = [], $relative = false) { $request = $this->requestStack->getCurrentRequest(); - + if ($request->query->has('returnPath')) { $parameters['returnPath'] = $request->query->get('returnPath'); } - + return $this->originalExtension ->getPath( - $name, + $name, $parameters, $relative ); } + /** + * Return the return path if it exists, or generate the path if not. + * + * @param string $name + * @param array $parameters + * @param bool $relative + * + * @return string + */ + public function getReturnPathOr($name, $parameters = [], $relative = false) + { + $request = $this->requestStack->getCurrentRequest(); + + if ($request->query->has('returnPath')) { + return $request->query->get('returnPath'); + } + + return $this->originalExtension->getPath($name, $parameters, $relative); + } + + public function isUrlGenerationSafe(Node $argsNode) + { + return $this->originalExtension->isUrlGenerationSafe($argsNode); + } } diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/AbstractChillEntityRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/AbstractChillEntityRender.php index d88c4b86f..57a6dfa04 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/AbstractChillEntityRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/AbstractChillEntityRender.php @@ -1,38 +1,23 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Templating\Entity; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Templating\Entity; + abstract class AbstractChillEntityRender implements ChillEntityRenderInterface { - protected function getDefaultOpeningBox($classSuffix): string - { - return ''; - } - protected function getDefaultClosingBox(): string { return ''; } + + protected function getDefaultOpeningBox($classSuffix): string + { + return ''; + } } diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRender.php index 8f8f58263..fc543ab3f 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRender.php @@ -1,34 +1,23 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\Entity; /** - * Render an entity using `__toString()` + * Render an entity using `__toString()`. */ class ChillEntityRender extends AbstractChillEntityRender { public function renderBox($entity, array $options): string { - return $this->getDefaultOpeningBox('default').$entity - .$this->getDefaultClosingBox(); + return $this->getDefaultOpeningBox('default') . $entity + . $this->getDefaultClosingBox(); } public function renderString($entity, array $options): string diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderExtension.php b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderExtension.php index 32aa12d85..2d7e3bec9 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderExtension.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderExtension.php @@ -1,45 +1,32 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\Entity; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; /** - * Class ChillEntityRenderExtension - * - * @package Chill\MainBundle\Templating\Entity + * Class ChillEntityRenderExtension. */ class ChillEntityRenderExtension extends AbstractExtension { - /** - * @var ChillEntityRenderInterface - */ - protected $renders = []; - /** * @var ChillEntityRender */ protected $defaultRender; - + + /** + * @var ChillEntityRenderInterface + */ + protected $renders = []; + /** * ChillEntityRenderExtension constructor. */ @@ -47,7 +34,12 @@ class ChillEntityRenderExtension extends AbstractExtension { $this->defaultRender = new ChillEntityRender(); } - + + public function addRender(ChillEntityRenderInterface $render) + { + $this->renders[] = $render; + } + /** * @return array|TwigFilter[] */ @@ -55,54 +47,43 @@ class ChillEntityRenderExtension extends AbstractExtension { return [ new TwigFilter('chill_entity_render_string', [$this, 'renderString'], [ - 'is_safe' => [ 'html' ] + 'is_safe' => ['html'], ]), new TwigFilter('chill_entity_render_box', [$this, 'renderBox'], [ - 'is_safe' => [ 'html' ] - ]) + 'is_safe' => ['html'], + ]), ]; } - + /** * @param $entity - * @param array $options - * @return string - */ - public function renderString($entity, array $options = []): string - { - if (NULL === $entity) { - return ''; - } - return $this->getRender($entity, $options) - ->renderString($entity, $options); - } - - /** - * @param $entity - * @param array $options - * @return string */ public function renderBox($entity, array $options = []): string { - if (NULL === $entity) { + if (null === $entity) { return ''; } + return $this->getRender($entity, $options) ->renderBox($entity, $options); } - + /** - * @param ChillEntityRenderInterface $render + * @param $entity */ - public function addRender(ChillEntityRenderInterface $render) + public function renderString($entity, array $options = []): string { - $this->renders[] = $render; + if (null === $entity) { + return ''; + } + + return $this->getRender($entity, $options) + ->renderString($entity, $options); } - + /** * @param $entity * @param $options - * @return ChillEntityRenderInterface|null */ protected function getRender($entity, $options): ?ChillEntityRenderInterface { @@ -111,6 +92,7 @@ class ChillEntityRenderExtension extends AbstractExtension return $render; } } + return $this->defaultRender; } } diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderInterface.php b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderInterface.php index d43ac3e52..d570ddd22 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderInterface.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/ChillEntityRenderInterface.php @@ -1,23 +1,12 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\Entity; /** @@ -27,40 +16,34 @@ namespace Chill\MainBundle\Templating\Entity; interface ChillEntityRenderInterface { /** - * Return true if the class support this object for the given options - * - * @param type $entity - * @param array $options - * @return bool - */ - public function supports($entity, array $options): bool; - - /** - * Return the entity as a string. - * - * Example: returning the name of a person. - * - * @param object $entity - * @param array $options - * @return string - */ - public function renderString($entity, array $options): string; - - /** - * Return the entity in a box - * + * Return the entity in a box. + * * Example: return a person inside a box: - * + * * ```html * * Roger * Dupont * * ``` - * + * * @param type $entity - * @param array $options - * @return string */ public function renderBox($entity, array $options): string; + + /** + * Return the entity as a string. + * + * Example: returning the name of a person. + * + * @param object $entity + */ + public function renderString($entity, array $options): string; + + /** + * Return true if the class support this object for the given options. + * + * @param type $entity + */ + public function supports($entity, array $options): bool; } diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php index 9ff0ca90c..ec6ce1cbf 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/CommentRender.php @@ -1,43 +1,32 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\Entity; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; use Chill\MainBundle\Repository\UserRepository; -use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; use Symfony\Component\Templating\EngineInterface; +use function array_merge; + class CommentRender extends AbstractChillEntityRender { /** - * @var \Chill\MainBundle\Repository\UserRepository - */ - private $userRepository; - - /** - * * @var EngineInterface */ private $engine; + /** + * @var \Chill\MainBundle\Repository\UserRepository + */ + private $userRepository; + public function __construct( UserRepository $userRepository, EngineInterface $engine @@ -48,42 +37,36 @@ class CommentRender extends AbstractChillEntityRender /** * @param CommentEmbeddable $entity - * @param array $options - * - * @return string */ public function renderBox($entity, array $options): string { // default options - $options = \array_merge([ - 'user' => [], - 'disable_markdown' => false, - 'limit_lines' => null, - 'metadata' => true - ], $options); - + $options = array_merge([ + 'user' => [], + 'disable_markdown' => false, + 'limit_lines' => null, + 'metadata' => true, + ], $options); + if ($entity->getUserId()) { $user = $this->userRepository->find($entity->getUserId()); } - + return $this->engine ->render( '@ChillMain/Entity/CommentEmbeddable.html.twig', [ 'opening_box' => $this->getDefaultOpeningBox('comment-embeddable'), 'closing_box' => $this->getDefaultClosingBox(), - 'user' => $user ?? NULL, + 'user' => $user ?? null, 'comment' => $entity, - 'options' => $options + 'options' => $options, ] ); } /** * @param CommentEmbeddable $entity - * @param array $options - * - * @return string */ public function renderString($entity, array $options): string { diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/CompilerPass.php b/src/Bundle/ChillMainBundle/Templating/Entity/CompilerPass.php index 7c25d2423..9f2af4139 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/CompilerPass.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/CompilerPass.php @@ -1,39 +1,27 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\Entity; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** - * Add service tagged with `chill.render_entity` to appropriate service - * + * Add service tagged with `chill.render_entity` to appropriate service. */ class CompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { $extension = $container->getDefinition(ChillEntityRenderExtension::class); - + foreach ($container->findTaggedServiceIds('chill.render_entity') as $id => $tags) { $extension->addMethodCall('addRender', [new Reference($id)]); } diff --git a/src/Bundle/ChillMainBundle/Templating/Events/DelegatedBlockRenderingEvent.php b/src/Bundle/ChillMainBundle/Templating/Events/DelegatedBlockRenderingEvent.php index 6e554d1be..f5ba84198 100644 --- a/src/Bundle/ChillMainBundle/Templating/Events/DelegatedBlockRenderingEvent.php +++ b/src/Bundle/ChillMainBundle/Templating/Events/DelegatedBlockRenderingEvent.php @@ -1,85 +1,73 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Templating\Events; +use ArrayAccess; +use RuntimeException; use Symfony\Component\EventDispatcher\Event; /** - * This event is transmitted on event chill_block.* - * - * You may access to the context as an array : - * + * This event is transmitted on event chill_block.*. + * + * You may access to the context as an array : + * * ``` * $var = $event['context_key'] * ``` - * - * The documentation for the bundle where the event is launched should give + * + * The documentation for the bundle where the event is launched should give * you the context keys. - * + * * The keys are read-only: if you try to update the context using array access * (example, using `$event['context_key'] = $bar;`, an error will be thrown. - * - * - * @author Julien Fastré */ -class DelegatedBlockRenderingEvent extends Event implements \ArrayAccess +class DelegatedBlockRenderingEvent extends Event implements ArrayAccess { /** - * - * @var mixed[] - */ - protected $context; - - /** - * The returned content of the event + * The returned content of the event. * * @var string */ protected $content = ''; - + + /** + * @var mixed[] + */ + protected $context; + public function __construct(array $context) { $this->context = $context; } - + /** * add content to the event. This content will be printed in the - * layout which launched the event - * + * layout which launched the event. + * * @param string $text */ public function addContent($text) { $this->content .= $text; } - + /** - * the content of the event - * + * the content of the event. + * * @return string */ public function getContent() { return $this->content; } - + public function offsetExists($offset) { return isset($this->context[$offset]); @@ -92,14 +80,13 @@ class DelegatedBlockRenderingEvent extends Event implements \ArrayAccess public function offsetSet($offset, $value) { - throw new \RuntimeException("The event context is read-only, you are not " - . "allowed to update it."); + throw new RuntimeException('The event context is read-only, you are not ' + . 'allowed to update it.'); } public function offsetUnset($offset) { - throw new \RuntimeException("The event context is read-only, you are not " - . "allowed to update it."); + throw new RuntimeException('The event context is read-only, you are not ' + . 'allowed to update it.'); } - } diff --git a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php index 673b87dbe..010d7fc8f 100644 --- a/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php +++ b/src/Bundle/ChillMainBundle/Templating/TranslatableStringHelper.php @@ -1,20 +1,10 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Templating; @@ -23,70 +13,58 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Translation\Translator; /** - * - * This helper helps to find the string in current locale from translatable_strings - * - * @author Julien Fastré - * + * This helper helps to find the string in current locale from translatable_strings. */ class TranslatableStringHelper { + private $fallbackLocales; + /** - * * @var RequestStack */ private $requestStack; - - private $fallbackLocales; - + public function __construct(RequestStack $requestStack, Translator $translator) { $this->requestStack = $requestStack; $this->fallbackLocales = $translator->getFallbackLocales(); } - + /** * 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; + if (null === $translatableStrings) { + return null; } - + $language = $this->requestStack->getCurrentRequest()->getLocale(); - if (isset($translatableStrings[$language])) { - return $translatableStrings[$language]; - } else { - foreach ($this->fallbackLocales as $locale) { - if (array_key_exists($locale, $translatableStrings)) { - - return $translatableStrings[$locale]; - } - } - } - + + foreach ($this->fallbackLocales as $locale) { + if (array_key_exists($locale, $translatableStrings)) { + return $translatableStrings[$locale]; + } + } + // no fallback translation... trying the first available $langs = array_keys($translatableStrings); - + if (count($langs) === 0) { return ''; } - + return $translatableStrings[$langs[0]]; - } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillMainBundle/Templating/TranslatableStringTwig.php b/src/Bundle/ChillMainBundle/Templating/TranslatableStringTwig.php index e2d89e8d1..39be0150b 100644 --- a/src/Bundle/ChillMainBundle/Templating/TranslatableStringTwig.php +++ b/src/Bundle/ChillMainBundle/Templating/TranslatableStringTwig.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Templating; @@ -28,41 +16,35 @@ use Twig\TwigFilter; class TranslatableStringTwig extends AbstractExtension { use ContainerAwareTrait; - + /** - * @var TranslatableStringHelper $helper + * @var TranslatableStringHelper */ private $helper; - + /** * TranslatableStringTwig constructor. - * - * @param TranslatableStringHelper $translatableStringHelper */ public function __construct(TranslatableStringHelper $translatableStringHelper) { $this->helper = $translatableStringHelper; } - + /* * Returns a list of filters to add to the existing list. - * + * * (non-PHPdoc) * @see Twig_Extension::getFilters() */ public function getFilters() { - return array( + return [ new TwigFilter( - 'localize_translatable_string', array($this, 'localize'))); + 'localize_translatable_string', + [$this, 'localize'] + ), ]; } - - public function localize(array $translatableStrings) - { - return $this->helper - ->localize($translatableStrings); - } - + /* * Returns the name of the extension. * @@ -73,4 +55,9 @@ class TranslatableStringTwig extends AbstractExtension return 'chill_main_localize'; } -} \ No newline at end of file + public function localize(array $translatableStrings) + { + return $this->helper + ->localize($translatableStrings); + } +} diff --git a/src/Bundle/ChillMainBundle/Templating/UI/CountNotificationUser.php b/src/Bundle/ChillMainBundle/Templating/UI/CountNotificationUser.php index 859cb673a..2440aaea2 100644 --- a/src/Bundle/ChillMainBundle/Templating/UI/CountNotificationUser.php +++ b/src/Bundle/ChillMainBundle/Templating/UI/CountNotificationUser.php @@ -1,51 +1,40 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Templating\UI; - -use Symfony\Component\Security\Core\User\UserInterface; -use Chill\MainBundle\Entity\User; /** - * Show a number of notification to user in the upper right corner + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Templating\UI; + +use Chill\MainBundle\Entity\User; +use Symfony\Component\Security\Core\User\UserInterface; + +/** + * Show a number of notification to user in the upper right corner. */ class CountNotificationUser { /** - * * @var NotificationCounterInterface[] */ protected $counters = []; - + public function addNotificationCounter(NotificationCounterInterface $counter) { $this->counters[] = $counter; } - + public function getSumNotification(UserInterface $u): int { - $sum = 0; - + $sum = 0; + foreach ($this->counters as $counter) { $sum += $counter->addNotification($u); } - + return $sum; } } diff --git a/src/Bundle/ChillMainBundle/Templating/UI/NotificationCounterInterface.php b/src/Bundle/ChillMainBundle/Templating/UI/NotificationCounterInterface.php index f0621b81a..1ab8e86d4 100644 --- a/src/Bundle/ChillMainBundle/Templating/UI/NotificationCounterInterface.php +++ b/src/Bundle/ChillMainBundle/Templating/UI/NotificationCounterInterface.php @@ -1,32 +1,20 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Templating\UI; use Symfony\Component\Security\Core\User\UserInterface; -/** - * - * @author Julien Fastré - */ interface NotificationCounterInterface { /** - * Add a number of notification + * Add a number of notification. */ public function addNotification(UserInterface $u): int; } diff --git a/src/Bundle/ChillMainBundle/Templating/Widget/WidgetInterface.php b/src/Bundle/ChillMainBundle/Templating/Widget/WidgetInterface.php index a768f0766..b378a2de1 100644 --- a/src/Bundle/ChillMainBundle/Templating/Widget/WidgetInterface.php +++ b/src/Bundle/ChillMainBundle/Templating/Widget/WidgetInterface.php @@ -1,5 +1,12 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Templating\Widget; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Chill\MainBundle\Templating\Widget\WidgetInterface; use Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Twig\Environment; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; +use function ksort; + /** * Add the function `chill_delegated_block`. - * + * * In a template, you can now allow rendering of a block from other bundle. - * + * * The layout template must explicitly call the rendering of other block, * with the twig function - * + * * ``` * chill_delegated_block('block_name', { 'array' : 'with context' } ) * ``` - * + * * This will launch an event * `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent` with * the event's name 'chill_block.block_name'. - * + * * You may add content to the page using the function * `DelegatedBlockRenderingEvent::addContent`. - * - * See also the documentation of + * + * See also the documentation of * `Chill\MainBundle\Templating\Events\DelegatedBlockRenderingEvent` * for usage of this event class - * - * - * @author Julien Fastré */ class WidgetRenderingTwig extends AbstractExtension { - /** - * Contains the widget. This is a double dimension array : - * - * - first key is the place, - * - second key is the ordering ; - * - the value is an array where the widget is the first argument and the - * second is the config - * - * i.e : - * - * $widget['place']['ordering'] = array($widget, $config); - * - * - * - * @var array an array of widget by place and ordering - */ - protected $widget = array(); - - /** - * * @var EventDispatcherInterface */ protected $eventDispatcher; - + + /** + * Contains the widget. This is a double dimension array :. + * + * - first key is the place, + * - second key is the ordering ; + * - the value is an array where the widget is the first argument and the + * second is the config + * + * i.e : + * + * $widget['place']['ordering'] = array($widget, $config); + * + * @var array an array of widget by place and ordering + */ + protected $widget = []; + public function __construct(EventDispatcherInterface $eventDispatcher) { $this->eventDispatcher = $eventDispatcher; } - - + + /** + * add a widget to this class, which become available for a future call. + * + * This function is used by DependencyInjection\CompilerPass\WidgetCompilerPass, + * which add the widget to this class when it is created by from DI, according + * to the given config under `chill_main`. + * + * @param string $place + * @param WidgetInterface $widget + * @param mixed $ordering + */ + public function addWidget($place, $ordering, $widget, array $config = []) + { + $this->widget[$place][$ordering] = [$widget, $config]; + } + + public function getFunctions() + { + return [ + new TwigFunction( + 'chill_delegated_block', + [$this, 'renderingWidget'], + [ + 'is_safe' => ['html'], + 'needs_environment' => true, + 'deprecated' => true, 'alternative' => 'chill_widget', + ] + ), + new TwigFunction( + 'chill_widget', + [$this, 'renderingWidget'], + ['is_safe' => ['html'], 'needs_environment' => true] + ), + ]; + } + public function getName() { return 'chill_main_widget'; } - - public function getFunctions() - { - return array( - new TwigFunction('chill_delegated_block', - array($this, 'renderingWidget'), - array( - 'is_safe' => array('html'), - 'needs_environment' => true, - 'deprecated' => true, 'alternative' => 'chill_widget' - )), - new TwigFunction('chill_widget', - array($this, 'renderingWidget'), - array('is_safe' => array('html'), 'needs_environment' => true)) - ); - } - - public function renderingWidget(Environment $env, $block, array $context = array()) + + public function renderingWidget(Environment $env, $block, array $context = []) { // get the content of widgets $content = ''; + foreach ($this->getWidgetsArraysOrdered($block) as $a) { /* @var $widget Widget\WidgetInterface */ $widget = $a[0]; $config = $a[1]; - + $content .= $widget->render($env, $block, $context, $config); } - + // for old rendering events (deprecated) $event = new DelegatedBlockRenderingEvent($context); - - $this->eventDispatcher->dispatch('chill_block.'.$block, $event); - - return $content." ".$event->getContent(); + + $this->eventDispatcher->dispatch('chill_block.' . $block, $event); + + return $content . ' ' . $event->getContent(); } - + /** - * add a widget to this class, which become available for a future call. - * - * This function is used by DependencyInjection\CompilerPass\WidgetCompilerPass, - * which add the widget to this class when it is created by from DI, according - * to the given config under `chill_main`. - * - * @param string $place - * @param WidgetInterface $widget - * @param array $config - */ - public function addWidget($place, $ordering, $widget, array $config = array()) - { - $this->widget[$place][$ordering] = array($widget, $config); - } - - /** - * * @param string $place + * * @return array */ protected function getWidgetsArraysOrdered($place) { if (!array_key_exists($place, $this->widget)) { - $this->widget[$place] = array(); + $this->widget[$place] = []; } - - \ksort($this->widget[$place]); - + + ksort($this->widget[$place]); + return $this->widget[$place]; } - - - } diff --git a/src/Bundle/ChillMainBundle/Test/Export/AbstractAggregatorTest.php b/src/Bundle/ChillMainBundle/Test/Export/AbstractAggregatorTest.php index d33a6f88d..eb445faf5 100644 --- a/src/Bundle/ChillMainBundle/Test/Export/AbstractAggregatorTest.php +++ b/src/Bundle/ChillMainBundle/Test/Export/AbstractAggregatorTest.php @@ -1,238 +1,253 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Test\Export; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\AbstractQuery; +use Doctrine\ORM\QueryBuilder; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Traversable; /** * Helper which creates a set of test for aggregators. * - * @author Julien Fastré + * @internal */ abstract class AbstractAggregatorTest extends KernelTestCase { /** - * Create an aggregator instance which will be used in tests. - * - * This method is always used after an eventuel `setUp` method. - * - * @return \Chill\MainBundle\Export\AggregatorInterface - */ - abstract public function getAggregator(); - - /** - * Create possible combinaison of data (produced by the form). - * - * This data will be used to generate data providers using this data. - * - * This method is executed before the `setUp` method. - * - * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values - */ - public abstract function getFormData(); - - /** - * get an array of query builders that the aggregator will use. - * - * Those query builders will be used to test aggregator behaviour on this - * query builder. - * - * This method is executed before the `setUp` method. - * - * @return \Doctrine\DBAL\Query\QueryBuilder[] - */ - public abstract function getQueryBuilders(); - - /** - * prepare data for `testGetQueryKeys` - */ - public function dataProviderGetQueryKeys() - { - foreach ($this->getFormData() as $data) { - yield array($data); - } - } - - /** - * prepare date for method `testGetResultsAndLabels` - */ - public function dataProviderGetResultsAndLabels() - { - foreach ($this->getQueryBuilders() as $qb) { - foreach ($this->getFormData() as $data) { - yield array(clone $qb, $data); - } - } - } - - /** - * provide data for `testAlterQuery` + * provide data for `testAlterQuery`. */ public function dataProviderAlterQuery() { foreach ($this->getQueryBuilders() as $qb) { foreach ($this->getFormData() as $data) { - yield array(clone $qb, $data); + yield [clone $qb, $data]; } } } - + + /** + * prepare data for `testGetQueryKeys`. + */ + public function dataProviderGetQueryKeys() + { + foreach ($this->getFormData() as $data) { + yield [$data]; + } + } + + /** + * prepare date for method `testGetResultsAndLabels`. + */ + public function dataProviderGetResultsAndLabels() + { + foreach ($this->getQueryBuilders() as $qb) { + foreach ($this->getFormData() as $data) { + yield [clone $qb, $data]; + } + } + } + + /** + * Create an aggregator instance which will be used in tests. + * + * This method is always used after an eventuel `setUp` method. + * + * @return \Chill\MainBundle\Export\AggregatorInterface + */ + abstract public function getAggregator(); + + /** + * Create possible combinaison of data (produced by the form). + * + * This data will be used to generate data providers using this data. + * + * This method is executed before the `setUp` method. + * + * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values + */ + abstract public function getFormData(); + + /** + * get an array of query builders that the aggregator will use. + * + * Those query builders will be used to test aggregator behaviour on this + * query builder. + * + * This method is executed before the `setUp` method. + * + * @return \Doctrine\DBAL\Query\QueryBuilder[] + */ + abstract public function getQueryBuilders(); + + /** + * test the alteration of query by the filter. + * + * @dataProvider dataProviderAlterQuery + * + * @param type $data + */ + public function testAlterQuery(QueryBuilder $query, $data) + { + // retains informations about query + $nbOfFrom = $query->getDQLPart('from') !== null ? + count($query->getDQLPart('from')) : 0; + $nbOfWhere = $query->getDQLPart('where') !== null ? + $query->getDQLPart('where')->count() : 0; + $nbOfSelect = $query->getDQLPart('select') !== null ? + count($query->getDQLPart('select')) : 0; + + $this->getAggregator()->alterQuery($query, $data); + + $this->assertGreaterThanOrEqual( + $nbOfFrom, + $query->getDQLPart('from') !== null ? count($query->getDQLPart('from')) : 0, + "Test that there are equal or more 'from' clause after that the filter has + altered the query" + ); + $this->assertGreaterThanOrEqual( + $nbOfWhere, + $query->getDQLPart('where') !== null ? $query->getDQLPart('where')->count() : 0, + "Test that there are equal or more 'where' clause after that the filter has" + . 'altered the query' + ); + $this->assertGreaterThanOrEqual( + $nbOfSelect, + $query->getDQLPart('select') !== null ? count($query->getDQLPart('select')) : 0, + "Test that the filter has no altered the 'select' part of the query" + ); + } + /** * Test the `applyOn` method. */ public function testApplyOn() { $filter = $this->getAggregator(); - - $this->assertInternalType('string', $filter->applyOn(), - "test that the internal type of \"applyOn\" is a string"); - $this->assertNotEmpty($filter->applyOn(), - "test that the \"applyOn\" method return a non-empty string"); + + $this->assertInternalType( + 'string', + $filter->applyOn(), + 'test that the internal type of "applyOn" is a string' + ); + $this->assertNotEmpty( + $filter->applyOn(), + 'test that the "applyOn" method return a non-empty string' + ); } - + /** - * test the `getTitle` method - */ - public function testGetTitle() - { - $title = $this->getAggregator()->getTitle(); - - $this->assertInternalType('string', $title); - $this->assertNotEmpty($title, - "test that the title is not empty"); - } - - /** - * Test that the query keys are strings - * - * @param array $data + * Test that the query keys are strings. + * * @dataProvider dataProviderGetQueryKeys */ public function testGetQueryKeys(array $data) { $queryKeys = $this->getAggregator()->getQueryKeys($data); - - $this->assertInternalType('array', $queryKeys, - "test that the query keys returned are an array"); - $this->assertContainsOnly("string", $queryKeys, - "test that the query keys returned by `getQueryKeys` are only strings"); - $this->assertGreaterThanOrEqual(1, count($queryKeys), - "test that there are at least one query key returned"); + + $this->assertInternalType( + 'array', + $queryKeys, + 'test that the query keys returned are an array' + ); + $this->assertContainsOnly( + 'string', + $queryKeys, + 'test that the query keys returned by `getQueryKeys` are only strings' + ); + $this->assertGreaterThanOrEqual( + 1, + count($queryKeys), + 'test that there are at least one query key returned' + ); } - + /** - * - * Test that - * + * Test that. + * * - the results have a correct form (are arrays or traversable) * - each key in a row are present in getQueryKeys ; * - each returned object of the `getLabels` method is callable * - each result can be converted to string using this callable * - each of this callable can provide a string for '_header' - * - * @param QueryBuilder $qb - * @param array $data - * + * * @dataProvider dataProviderGetResultsAndLabels */ public function testGetResultsAndLabels(QueryBuilder $qb, array $data) { // it is more convenient to group the `getResult` and `getLabels` test // due to the fact that testing both methods use the same tools. - + // limit the result for the query for performance reason $qb->setMaxResults(1); - + $queryKeys = $this->getAggregator()->getQueryKeys($data); $this->getAggregator()->alterQuery($qb, $data); - + $results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY); - + if (count($results) === 0) { - $this->markTestIncomplete("The result is empty. We cannot process tests " - . "on results"); + $this->markTestIncomplete('The result is empty. We cannot process tests ' + . 'on results'); } - + // testing the result $result = $results[0]; - - $this->assertTrue( $result instanceof \Traversable || is_array($result), - "test that each row in the result is traversable or an array"); - + + $this->assertTrue( + $result instanceof Traversable || is_array($result), + 'test that each row in the result is traversable or an array' + ); + foreach ($queryKeys as $key) { - $this->assertContains($key, array_keys($result), - "test that each key is present in `getQueryKeys`"); - - $closure = $this->getAggregator()->getLabels($key, array($result[$key]), $data); - - $this->assertTrue(is_callable($closure, false), - "test that the `getLabels` for key is a callable"); - $this->assertTrue(is_string((string) call_user_func($closure, $result[$key])), - sprintf("test that the callable return by `getLabels` for key %s " - . "is a string or an be converted to a string", $key)); - + $this->assertContains( + $key, + array_keys($result), + 'test that each key is present in `getQueryKeys`' + ); + + $closure = $this->getAggregator()->getLabels($key, [$result[$key]], $data); + + $this->assertTrue( + is_callable($closure, false), + 'test that the `getLabels` for key is a callable' + ); + $this->assertTrue( + is_string((string) call_user_func($closure, $result[$key])), + sprintf('test that the callable return by `getLabels` for key %s ' + . 'is a string or an be converted to a string', $key) + ); + $this->assertTrue( // conditions is_string((string) call_user_func($closure, '_header')) && !empty(call_user_func($closure, '_header')) && call_user_func($closure, '_header') !== '_header', // message - sprintf("Test that the callable return by `getLabels` for key %s " - . "can provide an header", $key) - ); + sprintf('Test that the callable return by `getLabels` for key %s ' + . 'can provide an header', $key) + ); } } - + /** - * test the alteration of query by the filter - * - * @dataProvider dataProviderAlterQuery - * @param QueryBuilder $query - * @param type $data + * test the `getTitle` method. */ - public function testAlterQuery(QueryBuilder $query, $data) + public function testGetTitle() { - // retains informations about query - $nbOfFrom = $query->getDQLPart('from') !== null ? - count($query->getDQLPart('from')) : 0; - $nbOfWhere = $query->getDQLPart('where') !== null ? - $query->getDQLPart('where')->count() : 0; - $nbOfSelect = $query->getDQLPart('select') !== null ? - count($query->getDQLPart('select')) : 0; - - $this->getAggregator()->alterQuery($query, $data); - - $this->assertGreaterThanOrEqual( - $nbOfFrom, - $query->getDQLPart('from') !== null ? count($query->getDQLPart('from')) : 0, - "Test that there are equal or more 'from' clause after that the filter has - altered the query"); - $this->assertGreaterThanOrEqual( - $nbOfWhere, - $query->getDQLPart('where') !== null ? $query->getDQLPart('where')->count() : 0, - "Test that there are equal or more 'where' clause after that the filter has" - . "altered the query"); - $this->assertGreaterThanOrEqual( - $nbOfSelect, - $query->getDQLPart('select') !== null ? count($query->getDQLPart('select')) : 0, - "Test that the filter has no altered the 'select' part of the query"); - + $title = $this->getAggregator()->getTitle(); + + $this->assertInternalType('string', $title); + $this->assertNotEmpty( + $title, + 'test that the title is not empty' + ); } } diff --git a/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php b/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php index d258c0d30..72db44dac 100644 --- a/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php +++ b/src/Bundle/ChillMainBundle/Test/Export/AbstractExportTest.php @@ -1,358 +1,403 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Test\Export; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\NativeQuery; -use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\Test\PrepareClientTrait; +use Doctrine\ORM\NativeQuery; +use Doctrine\ORM\QueryBuilder; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Role\Role; +use Traversable; /** * This class provide a set of tests for exports. - * + * * The tests provided by this class will check basic things, like * the type of value are conform to the expected, etc. * - * @author julien.fastre@champs-libres.coop + * @internal */ abstract class AbstractExportTest extends WebTestCase { - use PrepareClientTrait; - - /** - * Create an instance of the report to test - * - * @return \Chill\MainBundle\Export\ExportInterface an instance of the export to test - */ - public abstract function getExport(); - - /** - * Create possible combinaison of data (produced by the form). - * - * This data will be used to generate data providers using this data. - * - * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values - */ - public abstract function getFormData(); - - /** - * get the possible modifiers which could apply in combination to this - * export. - * . - * - * @return array of string[] an array which contains an array of possible modifiers. Example : `array( array('modifier_1', 'modifier_2'), array('modifier_1'), ...)` - */ - abstract public function getModifiersCombination(); - - /** - * Return an array usable as ACL - * - * If this method is overridden, the returned result must be an array - * with this form : - * - * ``` - * array( - * array( - * 'center' => //center instance - * 'circles' => array(// array of circles instances ) - * ) - * ); - * ``` - * - */ - public function getACL() + public function dataProviderGetQueryKeys() { - if (static::$kernel === null) { - static::bootKernel(); + foreach ($this->getFormData() as $data) { + yield [$data]; } - - $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - - $centers = $em->getRepository('ChillMainBundle:Center') - ->findAll(); - $circles = $em->getRepository('ChillMainBundle:Scope') - ->findAll(); - - if (count($centers) === 0) { - throw new \RuntimeException("No center found. Did you forget to " - . "run `doctrine:fixtures:load` command before ?"); - } - if (count($circles) === 0) { - throw new \RuntimeException("No circle found. Did you forget to " - . "run `doctrine:fixtures:load` command before ?"); - } - - return array([ - 'center' => $centers[0], - 'circles' => [ - $circles - ]]); } /** - * Test that the getType method return a string - */ - public function testGetType() - { - $export = $this->getExport(); - - $this->assertInternalType('string', $export->getType(), - "Assert that the `getType` method return a string"); - $this->assertNotEmpty($export->getType(), "Assert that the `getType` method" - . " does not return an empty string."); - } - - /** - * Test that the description is not empty - */ - public function testGetDescription() - { - $export = $this->getExport(); - - $this->assertInternalType('string', $export->getDescription(), - "Assert that the `getDescription` method return a string"); - $this->assertNotEmpty($export->getDescription(), - "Assert that the `getDescription` method does not return an empty " - . "string."); - } - - /** - * create data for `ìnitiateQuery` method + * create data for `ìnitiateQuery` method. */ public function dataProviderInitiateQuery() { $acl = $this->getAcl(); - - foreach($this->getModifiersCombination() as $modifiers) { - - foreach($this->getFormData() as $data) { - - yield array($modifiers, $acl, $data); + + foreach ($this->getModifiersCombination() as $modifiers) { + foreach ($this->getFormData() as $data) { + yield [$modifiers, $acl, $data]; } } } - - public function dataProviderGetQueryKeys() - { - foreach($this->getFormData() as $data) { - yield array($data); - } - } - + /** - * - * test that the query returned is a QueryBuilder or a NativeQuery. - * - * If the query is a QueryBuilder, test that select and from is not empty. - * - * If the query is a native sql, test the query is not empty (length is - * > 0). - * - * @dataProvider dataProviderInitiateQuery + * Return an array usable as ACL. + * + * If this method is overridden, the returned result must be an array + * with this form : + * + * ``` + * array( + * array( + * 'center' => //center instance + * 'circles' => array(// array of circles instances ) + * ) + * ); + * ``` */ - public function testInitiateQuery($modifiers, $acl, $data) + public function getACL() { - $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); - - $this->assertTrue($query instanceof QueryBuilder || $query instanceof NativeQuery, - sprintf("Assert that the returned query is an instance of %s or %s", - QueryBuilder::class, Query::class)); - - if ($query instanceof QueryBuilder) { - - $this->assertGreaterThanOrEqual(1, count($query->getDQLPart('select')), - "assert there is at least one 'select' part"); - - $this->assertGreaterThanOrEqual(1, count($query->getDQLPart('from')), - "assert there is at least one 'from' part"); - - } elseif ($query instanceof NativeQuery) { - $this->assertNotEmpty($query->getSQL(), - "check that the SQL query is not empty"); + if (null === static::$kernel) { + static::bootKernel(); } - } - - /** - * Test that supportsModifier return : - * - * - an array of string, if the query is a QueryBuilder ; - * - nothing, if the query is a native SQL - * - * @dataProvider dataProviderInitiateQuery - */ - public function testSupportsModifier($modifiers, $acl, $data) - { - $export = $this->getExport(); - $query = $export->initiateQuery($modifiers, $acl, $data); - - if ($query instanceof QueryBuilder) { - $this->assertContainsOnly('string', $export->supportsModifiers(), - "Test that the `supportsModifiers` method returns only strings"); - } elseif ($query instanceof NativeQuery) { - $this->assertTrue($export->supportsModifiers() === null || - count($export->supportsModifiers()) === 0, - "Test that the `supportsModifier` methods returns null or an empty array"); + + $em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + $centers = $em->getRepository('ChillMainBundle:Center') + ->findAll(); + $circles = $em->getRepository('ChillMainBundle:Scope') + ->findAll(); + + if (count($centers) === 0) { + throw new RuntimeException('No center found. Did you forget to ' + . 'run `doctrine:fixtures:load` command before ?'); } + + if (count($circles) === 0) { + throw new RuntimeException('No circle found. Did you forget to ' + . 'run `doctrine:fixtures:load` command before ?'); + } + + return [[ + 'center' => $centers[0], + 'circles' => [ + $circles, + ], ]]; } - + /** - * Test required role is an instance of Role + * Create an instance of the report to test. + * + * @return \Chill\MainBundle\Export\ExportInterface an instance of the export to test */ - public function testRequiredRole() - { - $role = $this->getExport()->requiredRole(); - - $this->assertInstanceOf(Role::class, $role, - sprintf("test that the returned value of `requiredRole` is an instance " - . "of %s", Role::class)); - } - + abstract public function getExport(); + /** - * Test the formatters type are string + * Create possible combinaison of data (produced by the form). + * + * This data will be used to generate data providers using this data. + * + * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values + */ + abstract public function getFormData(); + + /** + * get the possible modifiers which could apply in combination to this + * export. + * . + * + * @return array of string[] an array which contains an array of possible modifiers. Example : `array( array('modifier_1', 'modifier_2'), array('modifier_1'), ...)` + */ + abstract public function getModifiersCombination(); + + /** + * Test the formatters type are string. */ public function testGetAllowedFormattersType() { $formattersTypes = $this->getExport()->getAllowedFormattersTypes(); - - $this->assertContainsOnly("string", $formattersTypes, - "Test that the method `getAllowedFormattersTypes` returns an array of string"); + + $this->assertContainsOnly( + 'string', + $formattersTypes, + 'Test that the method `getAllowedFormattersTypes` returns an array of string' + ); } - + /** - * Test that the query keys are strings - * - * @param array $data + * Test that the description is not empty. + */ + public function testGetDescription() + { + $export = $this->getExport(); + + $this->assertInternalType( + 'string', + $export->getDescription(), + 'Assert that the `getDescription` method return a string' + ); + $this->assertNotEmpty( + $export->getDescription(), + 'Assert that the `getDescription` method does not return an empty ' + . 'string.' + ); + } + + /** + * Test that the query keys are strings. + * * @dataProvider dataProviderGetQueryKeys */ public function testGetQueryKeys(array $data) { $queryKeys = $this->getExport()->getQueryKeys($data); - - $this->assertContainsOnly("string", $queryKeys, - "test that the query keys returned by `getQueryKeys` are only strings"); - $this->assertGreaterThanOrEqual(1, count($queryKeys), - "test that there are at least one query key returned"); + + $this->assertContainsOnly( + 'string', + $queryKeys, + 'test that the query keys returned by `getQueryKeys` are only strings' + ); + $this->assertGreaterThanOrEqual( + 1, + count($queryKeys), + 'test that there are at least one query key returned' + ); } - + /** - * - * Test that - * + * Test that. + * * - the results have a correct form (are arrays or traversable) * - each key in a row are present in getQueryKeys ; * - each returned object of the `getLabels` method is callable * - each result can be converted to string using this callable * - each of this callable can provide a string for '_header' - * + * * @param string[] $modifiers * @param array $acl - * @param array $data - * + * * @dataProvider dataProviderInitiateQuery */ public function testGetResultsAndLabels($modifiers, $acl, array $data) { // it is more convenient to group the `getResult` and `getLabels` test // due to the fact that testing both methods use the same tools. - + $queryKeys = $this->getExport()->getQueryKeys($data); - $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); - + $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); + // limit the result for the query for performance reason (only for QueryBuilder, // not possible in NativeQuery) if ($query instanceof QueryBuilder) { $query->setMaxResults(1); - } - - $results = $this->getExport()->getResult($query, $data); - - $this->assertInternalType('array', $results, - "assert that the returned result is an array"); - - if (count($results) === 0) { - $this->markTestIncomplete("The result is empty. We cannot process tests " - . "on results"); } - + + $results = $this->getExport()->getResult($query, $data); + + $this->assertInternalType( + 'array', + $results, + 'assert that the returned result is an array' + ); + + if (count($results) === 0) { + $this->markTestIncomplete('The result is empty. We cannot process tests ' + . 'on results'); + } + // testing the result $result = $results[0]; - - $this->assertTrue( $result instanceof \Traversable || is_array($result), - "test that each row in the result is traversable or an array"); - + + $this->assertTrue( + $result instanceof Traversable || is_array($result), + 'test that each row in the result is traversable or an array' + ); + foreach ($result as $key => $value) { - $this->assertContains($key, $queryKeys, - "test that each key is present in `getQueryKeys`"); - - $closure = $this->getExport()->getLabels($key, array($value), $data); - - $this->assertTrue(is_callable($closure, false), - "test that the `getLabels` for key is a callable"); - $this->assertTrue(is_string((string) call_user_func($closure, $value)), - sprintf("test that the callable return by `getLabels` for key %s " - . "is a string or an be converted to a string", $key)); - + $this->assertContains( + $key, + $queryKeys, + 'test that each key is present in `getQueryKeys`' + ); + + $closure = $this->getExport()->getLabels($key, [$value], $data); + + $this->assertTrue( + is_callable($closure, false), + 'test that the `getLabels` for key is a callable' + ); + $this->assertTrue( + is_string((string) call_user_func($closure, $value)), + sprintf('test that the callable return by `getLabels` for key %s ' + . 'is a string or an be converted to a string', $key) + ); + $this->assertTrue( // conditions is_string((string) call_user_func($closure, '_header')) && !empty(call_user_func($closure, '_header')) && call_user_func($closure, '_header') !== '_header', // message - sprintf("Test that the callable return by `getLabels` for key %s " - . "can provide an header", $key) - ); - } - + sprintf('Test that the callable return by `getLabels` for key %s ' + . 'can provide an header', $key) + ); + } } - /** - * Test that the translated title of the export is present the list, - * and that the list of exports (under `/fr/exports/`) is still successfull + * Test that the getType method return a string. + */ + public function testGetType() + { + $export = $this->getExport(); + + $this->assertInternalType( + 'string', + $export->getType(), + 'Assert that the `getType` method return a string' + ); + $this->assertNotEmpty($export->getType(), 'Assert that the `getType` method' + . ' does not return an empty string.'); + } + + /** + * test that the query returned is a QueryBuilder or a NativeQuery. + * + * If the query is a QueryBuilder, test that select and from is not empty. + * + * If the query is a native sql, test the query is not empty (length is + * > 0). + * + * @dataProvider dataProviderInitiateQuery + * + * @param mixed $modifiers + * @param mixed $acl + * @param mixed $data + */ + public function testInitiateQuery($modifiers, $acl, $data) + { + $query = $this->getExport()->initiateQuery($modifiers, $acl, $data); + + $this->assertTrue( + $query instanceof QueryBuilder || $query instanceof NativeQuery, + sprintf( + 'Assert that the returned query is an instance of %s or %s', + QueryBuilder::class, + Query::class + ) + ); + + if ($query instanceof QueryBuilder) { + $this->assertGreaterThanOrEqual( + 1, + count($query->getDQLPart('select')), + "assert there is at least one 'select' part" + ); + + $this->assertGreaterThanOrEqual( + 1, + count($query->getDQLPart('from')), + "assert there is at least one 'from' part" + ); + } elseif ($query instanceof NativeQuery) { + $this->assertNotEmpty( + $query->getSQL(), + 'check that the SQL query is not empty' + ); + } + } + + /** + * Test that the translated title of the export is present the list, + * and that the list of exports (under `/fr/exports/`) is still successfull. */ public function testListExportPage() { /* @var $client \Symfony\Component\BrowserKit\Client */ $client = $this->getClient(); $export = $this->getExport(); - $prophet= new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $container = static::$kernel->getContainer(); - + // store the locale in a request $request = new Request(); $request->setLocale('fr'); $container->get('request_stack')->push($request); // translate the title - $title = $container->get('translator')->trans($export->getTitle()); - + $title = $container->get('translator')->trans($export->getTitle()); + // performs the request to /fr/exports $crawler = $client->request('GET', '/fr/exports/'); - + // and finally make tests - $this->assertTrue($client->getResponse()->isSuccessful(), - "test that the response of /fr/exports/ is successful"); - $this->assertContains($title, $crawler->text(), - "test that the page /fr/exports/ contains the title of the " - . "exports ('$title')"); + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'test that the response of /fr/exports/ is successful' + ); + $this->assertContains( + $title, + $crawler->text(), + 'test that the page /fr/exports/ contains the title of the ' + . "exports ('{$title}')" + ); + } + + /** + * Test required role is an instance of Role. + */ + public function testRequiredRole() + { + $role = $this->getExport()->requiredRole(); + + $this->assertInstanceOf( + Role::class, + $role, + sprintf('test that the returned value of `requiredRole` is an instance ' + . 'of %s', Role::class) + ); + } + + /** + * Test that supportsModifier return :. + * + * - an array of string, if the query is a QueryBuilder ; + * - nothing, if the query is a native SQL + * + * @dataProvider dataProviderInitiateQuery + * + * @param mixed $modifiers + * @param mixed $acl + * @param mixed $data + */ + public function testSupportsModifier($modifiers, $acl, $data) + { + $export = $this->getExport(); + $query = $export->initiateQuery($modifiers, $acl, $data); + + if ($query instanceof QueryBuilder) { + $this->assertContainsOnly( + 'string', + $export->supportsModifiers(), + 'Test that the `supportsModifiers` method returns only strings' + ); + } elseif ($query instanceof NativeQuery) { + $this->assertTrue( + $export->supportsModifiers() === null + || count($export->supportsModifiers()) === 0, + 'Test that the `supportsModifier` methods returns null or an empty array' + ); + } } } diff --git a/src/Bundle/ChillMainBundle/Test/Export/AbstractFilterTest.php b/src/Bundle/ChillMainBundle/Test/Export/AbstractFilterTest.php index 7721b9212..2c12b89df 100644 --- a/src/Bundle/ChillMainBundle/Test/Export/AbstractFilterTest.php +++ b/src/Bundle/ChillMainBundle/Test/Export/AbstractFilterTest.php @@ -1,190 +1,193 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Test\Export; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\QueryBuilder; +use Exception; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; /** - * Helper to test filters + * Helper to test filters. * - * @author Julien Fastré + * @internal */ abstract class AbstractFilterTest extends KernelTestCase { /** - * * @var \Prophecy\Prophet */ protected $prophet; - - /** - * Create a filter which will be used in tests. - * - * This method is always used after an eventuel `setUp` method. - * - * @return \Chill\MainBundle\Export\FilterInterface - */ - abstract public function getFilter(); - - /** - * Create possible combinaison of data (produced by the form). - * - * This data will be used to generate data providers using this data. - * - * As all data providers, this method is executed **before** calling - * the `setUp` method. - * - * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values - */ - public abstract function getFormData(); - - /** - * Return an array with different minimal query builders - * - * As all data providers, this method is executed **before** calling - * the `setUp` method. - * - * @return QueryBuilder[] an array of query builder - */ - public abstract function getQueryBuilders(); - - public function dataProviderAlterQuery() - { - foreach ($this->getQueryBuilders() as $qb) { - foreach ($this->getFormData() as $data) { - yield array($qb, $data); - } - } - } - - public function dataProviderDescriptionAction() - { - foreach ($this->getFormData() as $data) { - yield array($data); - } - } - + public function setUp() { $this->prepareProphet(); } - - - public function testApplyOn() + + public function dataProviderAlterQuery() { - $filter = $this->getFilter(); - - $this->assertInternalType('string', $filter->applyOn()); + foreach ($this->getQueryBuilders() as $qb) { + foreach ($this->getFormData() as $data) { + yield [$qb, $data]; + } + } } - + + public function dataProviderDescriptionAction() + { + foreach ($this->getFormData() as $data) { + yield [$data]; + } + } + /** - * test the alteration of query by the filter - * + * Create a filter which will be used in tests. + * + * This method is always used after an eventuel `setUp` method. + * + * @return \Chill\MainBundle\Export\FilterInterface + */ + abstract public function getFilter(); + + /** + * Create possible combinaison of data (produced by the form). + * + * This data will be used to generate data providers using this data. + * + * As all data providers, this method is executed **before** calling + * the `setUp` method. + * + * @return array an array of data. Example : `array( array(), array('fields' => array(1,2,3), ...)` where an empty array and `array(1,2,3)` are possible values + */ + abstract public function getFormData(); + + /** + * Return an array with different minimal query builders. + * + * As all data providers, this method is executed **before** calling + * the `setUp` method. + * + * @return QueryBuilder[] an array of query builder + */ + abstract public function getQueryBuilders(); + + /** + * test the alteration of query by the filter. + * * @dataProvider dataProviderAlterQuery - * @param QueryBuilder $query + * * @param type $data */ public function testAlterQuery(QueryBuilder $query, $data) { // retains informations about query - $nbOfFrom = $query->getDQLPart('from') !== null ? + $nbOfFrom = $query->getDQLPart('from') !== null ? count($query->getDQLPart('from')) : 0; - $nbOfWhere = $query->getDQLPart('where') !== null ? + $nbOfWhere = $query->getDQLPart('where') !== null ? $query->getDQLPart('where')->count() : 0; $nbOfSelect = $query->getDQLPart('select') !== null ? count($query->getDQLPart('select')) : 0; - + $this->getFilter()->alterQuery($query, $data); - + $this->assertGreaterThanOrEqual( - $nbOfFrom, + $nbOfFrom, $query->getDQLPart('from') !== null ? count($query->getDQLPart('from')) : 0, "Test that there are equal or more 'from' clause after that the filter has altered the query" - ); + ); $this->assertGreaterThanOrEqual( - $nbOfWhere, + $nbOfWhere, $query->getDQLPart('where') !== null ? $query->getDQLPart('where')->count() : 0, "Test that there are equal or more 'where' clause after that the filter has" - . "altered the query" - ); + . 'altered the query' + ); $this->assertEquals( - $nbOfSelect, + $nbOfSelect, $query->getDQLPart('select') !== null ? count($query->getDQLPart('select')) : 0, "Test that the filter has no altered the 'select' part of the query" - ); - + ); } - - public function testGetTitle() + + public function testApplyOn() { - $title = $this->getFilter()->getTitle(); - - $this->assertInternalType('string', $title); - $this->assertNotEmpty($title, - "test that the title is not empty"); + $filter = $this->getFilter(); + + $this->assertInternalType('string', $filter->applyOn()); } - + /** - * * @dataProvider dataProviderDescriptionAction + * * @param array $data */ public function testDescriptionAction($data) { $description = $this->getFilter()->describeAction($data); - + $this->assertTrue( is_string($description) || is_array($description), - "test that the description is a string or an array" - ); - + 'test that the description is a string or an array' + ); + if (is_string($description)) { - $this->assertNotEmpty($description, - "test that the description is not empty"); + $this->assertNotEmpty( + $description, + 'test that the description is not empty' + ); } elseif (is_array($description)) { - $this->assertInternalType('string', $description[0], - "test that the first element in the description array is a string"); - + $this->assertInternalType( + 'string', + $description[0], + 'test that the first element in the description array is a string' + ); + // test that the message is translated try { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $catalogue = static::$kernel->getContainer() ->get('translator') ->getCatalogue(); - - } catch (\Exception $ex) { + } catch (Exception $ex) { $this->markTestIncomplete( - sprintf("This test is incomplete due to %s thrown by 'translator' : %s, " - . "complete stack : %s", get_class($ex), $ex->getMessage(), - $ex->getTraceAsString())); + sprintf( + "This test is incomplete due to %s thrown by 'translator' : %s, " + . 'complete stack : %s', + get_class($ex), + $ex->getMessage(), + $ex->getTraceAsString() + ) + ); } - $this->assertTrue($catalogue->has($description[0], - isset($description[2]) ? $description[2] : 'messages'), - sprintf("Test that the message returned by getDescriptionAction is " - . "present in the catalogue of translations. HINT : check that \"%s\" " - . "is correctly translated", $description[0])); + $this->assertTrue( + $catalogue->has( + $description[0], + $description[2] ?? 'messages' + ), + sprintf('Test that the message returned by getDescriptionAction is ' + . 'present in the catalogue of translations. HINT : check that "%s" ' + . 'is correctly translated', $description[0]) + ); } - + } + + public function testGetTitle() + { + $title = $this->getFilter()->getTitle(); + + $this->assertInternalType('string', $title); + $this->assertNotEmpty( + $title, + 'test that the title is not empty' + ); } } diff --git a/src/Bundle/ChillMainBundle/Test/PrepareCenterTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareCenterTrait.php index 39d530a29..8c8bb96c5 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareCenterTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareCenterTrait.php @@ -1,59 +1,45 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test; - /** - * A trait to prepare center - * + * A trait to prepare center. + * * **Usage :** You must set up trait with `setUpTrait` before use * and use tearDownTrait after usage. * - * @author Julien Fastré * @codeCoverageIgnore */ trait PrepareCenterTrait { - private $centerProphet; - + /** - * prepare a mocked center, with and id and name given - * + * prepare a mocked center, with and id and name given. + * * @param int $id * @param string $name - * @return \Chill\MainBundle\Entity\Center + * + * @return \Chill\MainBundle\Entity\Center */ protected function prepareCenter($id, $name) { - - if ($this->centerProphet === NULL) { + if (null === $this->centerProphet) { $this->centerProphet = new \Prophecy\Prophet(); } - + $center = $this->centerProphet->prophesize(); $center->willExtend('\Chill\MainBundle\Entity\Center'); $center->getId()->willReturn($id); $center->getName()->willReturn($name); - + return $center->reveal(); } - } diff --git a/src/Bundle/ChillMainBundle/Test/PrepareCircleTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareCircleTrait.php index df150e556..eb9d0d7ac 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareCircleTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareCircleTrait.php @@ -1,57 +1,45 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test; /** - * A trait to prepare center - * + * A trait to prepare center. + * * **Usage :** You must set up trait with `setUpTrait` before use * and use tearDownTrait after usage. - * * - * @author Julien Fastré * @codeCoverageIgnore */ trait PrepareCircleTrait { private $circleProphet; - + /** - * prepare a mocked center, with and id and name given - * + * prepare a mocked center, with and id and name given. + * * @param int $id * @param string $name - * @return \Chill\MainBundle\Entity\Center + * + * @return \Chill\MainBundle\Entity\Center */ protected function prepareCircle($id, $name) { - - if ($this->circleProphet === NULL) { + if (null === $this->circleProphet) { $this->circleProphet = new \Prophecy\Prophet(); } - + $scope = $this->circleProphet->prophesize(); $scope->willExtend('\Chill\MainBundle\Entity\Scope'); $scope->getId()->willReturn($id); $scope->getName()->willReturn($name); - + return $scope->reveal(); } } diff --git a/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php index 0ae7c235a..818f6e21a 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareClientTrait.php @@ -1,51 +1,44 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Test; +use LogicException; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Prepare a client authenticated with a user - * - * @author Julien Fastré + * Prepare a client authenticated with a user. */ trait PrepareClientTrait { /** * Create a new client with authentication information. - * + * * @param string $username the username (default 'center a_social') * @param string $password the password (default 'password') + * + * @throws LogicException + * * @return \Symfony\Component\BrowserKit\Client - * @throws \LogicException */ public function getClientAuthenticated( - $username = 'center a_social', + $username = 'center a_social', $password = 'password' ) { if (!$this instanceof WebTestCase) { - throw new \LogicException(sprintf("The current class does not " - . "implements %s", WebTestCase::class)); + throw new LogicException(sprintf('The current class does not ' + . 'implements %s', WebTestCase::class)); } - - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => $password, - )); + + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => $password, + ]); } } diff --git a/src/Bundle/ChillMainBundle/Test/PrepareScopeTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareScopeTrait.php index 01de3c0f6..7ab4f7323 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareScopeTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareScopeTrait.php @@ -1,45 +1,36 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test; /** - * A trait to prepare center - * + * A trait to prepare center. + * * **Usage :** You must set up trait with `setUpTrait` before use * and use tearDownTrait after usage. - * * - * @author Julien Fastré * @codeCoverageIgnore + * * @deprecated use PrepareCircleTrait instead */ trait PrepareScopeTrait { use PrepareCircleTrait; - + /** - * prepare a mocked center, with and id and name given - * + * prepare a mocked center, with and id and name given. + * * @param int $id * @param string $name - * @return \Chill\MainBundle\Entity\Center + * + * @return \Chill\MainBundle\Entity\Center + * * @deprecated */ protected function prepareScope($id, $name) diff --git a/src/Bundle/ChillMainBundle/Test/PrepareUserTrait.php b/src/Bundle/ChillMainBundle/Test/PrepareUserTrait.php index 5eccf2770..27af36491 100644 --- a/src/Bundle/ChillMainBundle/Test/PrepareUserTrait.php +++ b/src/Bundle/ChillMainBundle/Test/PrepareUserTrait.php @@ -1,46 +1,34 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\GroupCenter; -use Chill\MainBundle\Entity\RoleScope; use Chill\MainBundle\Entity\PermissionsGroup; +use Chill\MainBundle\Entity\RoleScope; +use Chill\MainBundle\Entity\User; +use LogicException; /** - * A trait to prepare user with permission. May be used + * A trait to prepare user with permission. May be used * within tests. - * + * * **Usage : ** You must set up trait with `setUpTrait` before use * and use tearDownTrait after usage. - * * - * @author Julien Fastré * @codeCoverageIgnore */ trait PrepareUserTrait { - /** - * prepare a user with correct permissions - * + * prepare a user with correct permissions. + * * Example of permissions: * ``` * array( @@ -52,38 +40,36 @@ trait PrepareUserTrait * ) * ) * ``` - * Scope must be an int. Scope created have this int as id, and the + * Scope must be an int. Scope created have this int as id, and the * int converted to string as name. - * - * + * * @param array $permissions an array of permissions, with key 'center' for the center and key 'attrs' for an array of ['role' => (string), 'scope' => (int)] + * + * @throws LogicException if the trait is not set up + * * @return User - * @throws \LogicException if the trait is not set up */ protected function prepareUser(array $permissions) { $user = new User(); - + foreach ($permissions as $permission) { $groupCenter = (new GroupCenter()) - ->setCenter($permission['center']); + ->setCenter($permission['center']); $permissionGroup = new PermissionsGroup(); - + foreach ($permission['permissionsGroup'] as $pg) { - $roleScope = (new RoleScope()) - ->setRole($pg['role']) - ->setScope($pg['scope']); - ; + ->setRole($pg['role']) + ->setScope($pg['scope']); + $permissionGroup->addRoleScope($roleScope); - } - + $groupCenter->setPermissionsGroup($permissionGroup); $user->addGroupCenter($groupCenter); - - } - + } + return $user; } } diff --git a/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php b/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php index d471dd624..cf32299d6 100644 --- a/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php +++ b/src/Bundle/ChillMainBundle/Test/ProphecyTrait.php @@ -1,53 +1,38 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test; /** - * a trait to prepare prophecy - * + * a trait to prepare prophecy. + * * **Usage : ** You must set up trait with `setUpTrait` before use * and use tearDownTrait after usage. * - * @author Julien Fastré * @codeCoverageIgnore */ trait ProphecyTrait { - /** - * * @var \Prophecy\Prophet() */ private $prophet; - + /** - * * @return \Prophecy\Prophet */ public function getProphet() { - if ($this->prophet === NULL) { + if (null === $this->prophet) { $this->prophet = new \Prophecy\Prophet(); } - + return $this->prophet; } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/CenterControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/CenterControllerTest.php index ede351e8b..dd8074e4d 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/CenterControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/CenterControllerTest.php @@ -1,52 +1,71 @@ 'admin', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); // Create a new entry in the database $crawler = $client->request('GET', '/fr/admin/center/'); - $this->assertEquals(200, $client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /fr/admin/center/"); + $this->assertEquals( + 200, + $client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /fr/admin/center/' + ); $crawler = $client->click($crawler->selectLink('Créer un nouveau centre')->link()); // Fill in the form and submit it - $form = $crawler->selectButton('Créer')->form(array( - 'chill_mainbundle_center[name]' => 'Test center', - )); + $form = $crawler->selectButton('Créer')->form([ + 'chill_mainbundle_center[name]' => 'Test center', + ]); $client->submit($form); $crawler = $client->followRedirect(); // Check data in the show view - $this->assertGreaterThan(0, - $crawler->filter('td:contains("Test center")')->count(), - 'Missing element td:contains("Test center")'); + $this->assertGreaterThan( + 0, + $crawler->filter('td:contains("Test center")')->count(), + 'Missing element td:contains("Test center")' + ); // Edit the entity $crawler = $client->click($crawler->selectLink('Modifier')->link()); - $form = $crawler->selectButton('Mettre à jour')->form(array( - 'chill_mainbundle_center[name]' => 'Foo', - )); + $form = $crawler->selectButton('Mettre à jour')->form([ + 'chill_mainbundle_center[name]' => 'Foo', + ]); $client->submit($form); $crawler = $client->followRedirect(); // Check the element contains an attribute with value equals "Foo" - $this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), - 'Missing element [value="Foo"]'); + $this->assertGreaterThan( + 0, + $crawler->filter('[value="Foo"]')->count(), + 'Missing element [value="Foo"]' + ); $crawler = $client->request('GET', '/fr/admin/center/'); diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/ExportControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/ExportControllerTest.php index d75f2cc71..3f85c7d2e 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/ExportControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/ExportControllerTest.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Controller; @@ -22,24 +12,26 @@ namespace Chill\MainBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the export + * Test the export. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ExportControllerTest extends WebTestCase { public function testIndex() { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); - + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); + $client->request('GET', '/fr/exports/'); - $this->assertTrue($client->getResponse()->isSuccessful(), - "assert the list is shown"); + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'assert the list is shown' + ); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/LoginControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/LoginControllerTest.php index a621b897e..38a9de6a0 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/LoginControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/LoginControllerTest.php @@ -1,10 +1,21 @@ request('GET', '/login'); $this->assertTrue($client->getResponse()->isSuccessful()); - + $buttonCrawlerNode = $crawler->selectButton('login'); $form = $buttonCrawlerNode->form(); - - $client->submit($form, array( - '_username' => 'center a_social', - '_password' => 'password' - )); - + + $client->submit($form, [ + '_username' => 'center a_social', + '_password' => 'password', + ]); + //the response is a redirection $this->assertTrue($client->getResponse()->isRedirect()); - + //the response is not a login page, but on a new page $this->assertNotRegExp('/\/login$/', $client->getResponse() - ->headers - ->get('location')); - + ->headers + ->get('location')); + //on the home page, there must be a logout link $client->followRedirects(true); $crawler = $client->request('GET', '/'); - + $this->assertRegExp('/center a_social/', $client->getResponse() - ->getContent()); + ->getContent()); $logoutLinkFilter = $crawler->filter('a:contains("Se déconnecter")'); - + //check there is > 0 logout link $this->assertGreaterThan(0, $logoutLinkFilter->count(), 'check that a logout link is present'); - + //click on logout link $client->followRedirects(false); $client->click($crawler->selectLink('Se déconnecter')->link()); - + $this->assertTrue($client->getResponse()->isRedirect()); - $client->followRedirect(); #redirect to login page - + $client->followRedirect(); //redirect to login page + //check we are back on login page $this->assertRegExp('/\/login$/', $client->getResponse() - ->headers - ->get('location')); - - + ->headers + ->get('location')); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/PermissionsGroupControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/PermissionsGroupControllerTest.php index 9657c4800..aa64a8c91 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/PermissionsGroupControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/PermissionsGroupControllerTest.php @@ -1,15 +1,27 @@ markTestSkipped(); } + /* public function testCompleteScenario() { @@ -55,5 +67,5 @@ class PermissionsGroupControllerTest extends WebTestCase $this->assertNotRegExp('/Foo/', $client->getResponse()->getContent()); } - */ + */ } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/ScopeControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/ScopeControllerTest.php index ad8318002..0c848d9ac 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/ScopeControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/ScopeControllerTest.php @@ -1,30 +1,44 @@ 'admin', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); // Create a new entry in the database $crawler = $client->request('GET', '/fr/admin/scope/'); - $this->assertEquals(200, $client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /fr/admin/scope/"); + $this->assertEquals( + 200, + $client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /fr/admin/scope/' + ); $crawler = $client->click($crawler->selectLink('Créer un nouveau cercle')->link()); // Fill in the form and submit it - $form = $crawler->selectButton('Créer')->form(array( - 'chill_mainbundle_scope[name][fr]' => 'Test en fr', - 'chill_mainbundle_scope[name][en]' => 'Test en en' - )); + $form = $crawler->selectButton('Créer')->form([ + 'chill_mainbundle_scope[name][fr]' => 'Test en fr', + 'chill_mainbundle_scope[name][en]' => 'Test en en', + ]); $client->submit($form/*, array( 'chill_mainbundle_scope' => array( @@ -36,25 +50,26 @@ class ScopeControllerTest extends WebTestCase ) )*/); $crawler = $client->followRedirect(); - + // Check data in the show view - $this->assertGreaterThan(0, $crawler->filter('td:contains("Test en fr")')->count(), - 'Missing element td:contains("Test en fr")'); + $this->assertGreaterThan( + 0, + $crawler->filter('td:contains("Test en fr")')->count(), + 'Missing element td:contains("Test en fr")' + ); // Edit the entity $crawler = $client->click($crawler->selectLink('Modifier')->link()); - - $form = $crawler->selectButton('Mettre à jour')->form(array( - 'chill_mainbundle_scope[name][fr]' => 'Foo', - 'chill_mainbundle_scope[name][en]' => 'Foo en', - )); + + $form = $crawler->selectButton('Mettre à jour')->form([ + 'chill_mainbundle_scope[name][fr]' => 'Foo', + 'chill_mainbundle_scope[name][en]' => 'Foo en', + ]); $client->submit($form); $crawler = $client->followRedirect(); // Check the element contains an attribute with value equals "Foo" $this->assertGreaterThan(0, $crawler->filter('[value="Foo"]')->count(), 'Missing element [value="Foo"]'); - } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/SearchControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/SearchControllerTest.php index a78ed1f28..cda4c18e2 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/SearchControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/SearchControllerTest.php @@ -1,102 +1,98 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Chill\MainBundle\Search\SearchInterface; - - /** - * Test the search controller + * Test the search controller. * - * @author Julien Fastré + * @internal + * @coversNothing */ class SearchControllerTest extends WebTestCase { - + public function testDomainUnknow() + { + $client = $this->getAuthenticatedClient(); + + $crawler = $client->request('GET', '/fr/search', ['q' => '@unknow domain']); + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page is loaded without errors' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('*:contains("Le domaine de recherche "unknow" est inconnu.")')->count(), + 'Message domain unknow is shown' + ); + } + + public function testParsingIncorrect() + { + $client = $this->getAuthenticatedClient(); + + $crawler = $client->request( + 'GET', + '/fr/search', + ['q' => '@domaine @domain double domaine'] + ); + + $this->assertGreaterThan(0, $crawler->filter('*:contains("Recherche invalide")') + ->count()); + } + /** - * Test the behaviour when no domain is provided in the search pattern : - * the default search should be enabled + * Test the behaviour when no domain is provided in the search pattern : + * the default search should be enabled. */ public function testSearchPath() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array('q' => 'default search')); - $this->assertTrue($client->getResponse()->isSuccessful(), - "The page is loaded without errors"); - + $crawler = $client->request('GET', '/fr/search', ['q' => 'default search']); + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page is loaded without errors' + ); } - + public function testSearchPathEmpty() { $client = $this->getAuthenticatedClient(); - + $crawler = $client->request('GET', '/fr/search?q='); $this->assertGreaterThan(0, $crawler->filter('*:contains("Merci de fournir des termes de recherche.")')->count()); } - - public function testDomainUnknow() - { - $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array('q' => '@unknow domain')); - $this->assertTrue($client->getResponse()->isSuccessful(), - "The page is loaded without errors"); - $this->assertGreaterThan(0, $crawler->filter('*:contains("Le domaine de recherche "unknow" est inconnu.")')->count(), - "Message domain unknow is shown"); - - } - - public function testParsingIncorrect() - { - $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', - array('q' => '@domaine @domain double domaine')); - - $this->assertGreaterThan(0, $crawler->filter('*:contains("Recherche invalide")') - ->count()); - } - public function testUnknowName() { $client = $this->getAuthenticatedClient(); - - $client->request('GET', '/fr/search', - array('q' => 'default search', 'name' => 'unknow')); - + + $client->request( + 'GET', + '/fr/search', + ['q' => 'default search', 'name' => 'unknow'] + ); + $this->assertTrue($client->getResponse()->isNotFound()); } - + private function getAuthenticatedClient() { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center b_social', - 'PHP_AUTH_PW' => 'password', - )); + return static::createClient([], [ + 'PHP_AUTH_USER' => 'center b_social', + 'PHP_AUTH_PW' => 'password', + ]); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php index eeff4cc06..b0dc36f8e 100644 --- a/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Controller/UserControllerTest.php @@ -1,114 +1,118 @@ client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'admin', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR' - )); + + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr_FR', + ]); } public function testList() { // get the list $crawler = $this->client->request('GET', '/fr/admin/user/'); - $this->assertEquals(200, $this->client->getResponse()->getStatusCode(), - "Unexpected HTTP status code for GET /admin/user/"); - + $this->assertEquals( + 200, + $this->client->getResponse()->getStatusCode(), + 'Unexpected HTTP status code for GET /admin/user/' + ); + $link = $crawler->selectLink('Ajouter un nouvel utilisateur')->link(); $this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $link); $this->assertRegExp('|/fr/admin/user/new$|', $link->getUri()); } - + public function testNew() { $crawler = $this->client->request('GET', '/fr/admin/user/new'); - - $username = 'Test_user'. uniqid(); + + $username = 'Test_user' . uniqid(); $password = 'Password1234!'; dump($crawler->text()); // Fill in the form and submit it - $form = $crawler->selectButton('Créer')->form(array( - 'chill_mainbundle_user[username]' => $username, + $form = $crawler->selectButton('Créer')->form([ + 'chill_mainbundle_user[username]' => $username, 'chill_mainbundle_user[plainPassword][first]' => $password, - 'chill_mainbundle_user[plainPassword][second]' => $password - )); + 'chill_mainbundle_user[plainPassword][second]' => $password, + ]); $this->client->submit($form); $crawler = $this->client->followRedirect(); // Check data in the show view - $this->assertGreaterThan(0, $crawler->filter('td:contains("Test_user")')->count(), - 'Missing element td:contains("Test user")'); - + $this->assertGreaterThan( + 0, + $crawler->filter('td:contains("Test_user")')->count(), + 'Missing element td:contains("Test user")' + ); + $update = $crawler->selectLink('Modifier')->link(); - + $this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $update); $this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit$|', $update->getUri()); - + //test the auth of the new client $this->isPasswordValid($username, $password); - + return $update; } - - protected function isPasswordValid($username, $password) - { - /* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */ - $passwordEncoder = self::$kernel->getContainer() - ->get('security.password_encoder'); - - $user = self::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => $username)); - - $this->assertTrue($passwordEncoder->isPasswordValid($user, $password)); - } - + /** - * - * @param \Symfony\Component\DomCrawler\Link $update * @depends testNew */ public function testUpdate(\Symfony\Component\DomCrawler\Link $update) { $crawler = $this->client->click($update); - $username = 'Foo bar '.uniqid(); - $form = $crawler->selectButton('Mettre à jour')->form(array( - 'chill_mainbundle_user[username]' => $username, - )); - + $username = 'Foo bar ' . uniqid(); + $form = $crawler->selectButton('Mettre à jour')->form([ + 'chill_mainbundle_user[username]' => $username, + ]); + $this->client->submit($form); $crawler = $this->client->followRedirect(); // Check the element contains an attribute with value equals "Foo" - $this->assertGreaterThan(0, $crawler->filter('[value="'.$username.'"]')->count(), - 'Missing element [value="Foo bar"]'); - + $this->assertGreaterThan( + 0, + $crawler->filter('[value="' . $username . '"]')->count(), + 'Missing element [value="Foo bar"]' + ); + $updatePassword = $crawler->selectLink('Modifier le mot de passe')->link(); - + $this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $updatePassword); - $this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit_password$|', - $updatePassword->getUri()); - - return array('link' => $updatePassword, 'username' => $username); + $this->assertRegExp( + '|/fr/admin/user/[0-9]{1,}/edit_password$|', + $updatePassword->getUri() + ); + + return ['link' => $updatePassword, 'username' => $username]; } - + /** - * - * @param \Symfony\Component\DomCrawler\Link $updatePassword * @depends testUpdate */ public function testUpdatePassword(array $params) @@ -116,22 +120,36 @@ class UserControllerTest extends WebTestCase $link = $params['link']; $username = $params['username']; $newPassword = '1234Password!'; - + $crawler = $this->client->click($link); - - $form = $crawler->selectButton('Changer le mot de passe')->form(array( + + $form = $crawler->selectButton('Changer le mot de passe')->form([ 'chill_mainbundle_user_password[new_password][first]' => $newPassword, 'chill_mainbundle_user_password[new_password][second]' => $newPassword, - )); - + ]); + $this->client->submit($form); - - $this->assertTrue($this->client->getResponse()->isRedirect(), - "the response is a redirection"); + + $this->assertTrue( + $this->client->getResponse()->isRedirect(), + 'the response is a redirection' + ); $this->client->followRedirect(); - + $this->isPasswordValid($username, $newPassword); } - + protected function isPasswordValid($username, $password) + { + /* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */ + $passwordEncoder = self::$kernel->getContainer() + ->get('security.password_encoder'); + + $user = self::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:User') + ->findOneBy(['username' => $username]); + + $this->assertTrue($passwordEncoder->isPasswordValid($user, $password)); + } } diff --git a/src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php b/src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php index 5632bf96a..045397ecc 100644 --- a/src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Doctrine/Model/PointTest.php @@ -1,49 +1,73 @@ + * @internal + * @coversNothing */ class ExportControllerTest extends KernelTestCase { - - public function testToWKT() + public function testFromArrayGeoJson() { + $array = [ + 'type' => 'Point', + 'coordinates' => [4.8634, 50.47382], + ]; $lon = 4.8634; $lat = 50.47382; $point = $this->preparePoint($lon, $lat); - $this->assertEquals($point->toWKT(),'SRID=4326;POINT(4.8634 50.47382)'); + $this->assertEquals($point, Point::fromArrayGeoJson($array)); } - public function testToGeojson() + public function testFromGeoJson() { + $geojson = '{"type":"Point","coordinates":[4.8634,50.47382]}'; $lon = 4.8634; $lat = 50.47382; $point = $this->preparePoint($lon, $lat); - $this->assertEquals($point->toGeoJson(),'{"type":"Point","coordinates":[4.8634,50.47382]}'); + $this->assertEquals($point, Point::fromGeoJson($geojson)); } - public function testToArrayGeoJson() + public function testFromLonLat() { $lon = 4.8634; $lat = 50.47382; $point = $this->preparePoint($lon, $lat); - $this->assertEquals( - $point->toArrayGeoJson(), - [ - 'type' => 'Point', - 'coordinates' => [4.8634, 50.47382] - ] - ); + $this->assertEquals($point, Point::fromLonLat($lon, $lat)); + } + + public function testGetLat() + { + $lon = 4.8634; + $lat = 50.47382; + $point = $this->preparePoint($lon, $lat); + + $this->assertEquals($lat, $point->getLat()); + } + + public function testGetLon() + { + $lon = 4.8634; + $lat = 50.47382; + $point = $this->preparePoint($lon, $lat); + + $this->assertEquals($lon, $point->getLon()); } public function testJsonSerialize() @@ -56,64 +80,46 @@ class ExportControllerTest extends KernelTestCase $point->jsonSerialize(), [ 'type' => 'Point', - 'coordinates' => [4.8634, 50.47382] + 'coordinates' => [4.8634, 50.47382], ] ); } - public function testFromGeoJson() + public function testToArrayGeoJson() { - $geojson = '{"type":"Point","coordinates":[4.8634,50.47382]}'; $lon = 4.8634; $lat = 50.47382; - $point = $this->preparePoint($lon, $lat);; + $point = $this->preparePoint($lon, $lat); - $this->assertEquals($point, Point::fromGeoJson($geojson)); + $this->assertEquals( + $point->toArrayGeoJson(), + [ + 'type' => 'Point', + 'coordinates' => [4.8634, 50.47382], + ] + ); } - public function testFromLonLat() + public function testToGeojson() { $lon = 4.8634; $lat = 50.47382; - $point = $this->preparePoint($lon, $lat);; + $point = $this->preparePoint($lon, $lat); - $this->assertEquals($point, Point::fromLonLat($lon, $lat)); + $this->assertEquals($point->toGeoJson(), '{"type":"Point","coordinates":[4.8634,50.47382]}'); } - public function testFromArrayGeoJson() - { - $array = [ - 'type' => 'Point', - 'coordinates' => [4.8634, 50.47382] - ]; - $lon = 4.8634; - $lat = 50.47382; - $point = $this->preparePoint($lon, $lat);; - - $this->assertEquals($point, Point::fromArrayGeoJson($array)); - } - - public function testGetLat() + public function testToWKT() { $lon = 4.8634; $lat = 50.47382; - $point = $this->preparePoint($lon, $lat);; + $point = $this->preparePoint($lon, $lat); - $this->assertEquals($lat, $point->getLat()); - } - - public function testGetLon() - { - $lon = 4.8634; - $lat = 50.47382; - $point = $this->preparePoint($lon, $lat);; - - $this->assertEquals($lon, $point->getLon()); + $this->assertEquals($point->toWKT(), 'SRID=4326;POINT(4.8634 50.47382)'); } private function preparePoint($lon, $lat) { return Point::fromLonLat($lon, $lat); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php index d71997c9e..3f4edc17d 100644 --- a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php @@ -1,243 +1,395 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Export; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\MainBundle\Export\ExportManager; -use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\Export\AggregatorInterface; -use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Chill\MainBundle\Export\ExportInterface; -use Prophecy\Argument; -use Doctrine\ORM\QueryBuilder; +use Chill\MainBundle\Export\ExportManager; +use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\Export\ExportType; +use Doctrine\ORM\QueryBuilder; +use Prophecy\Argument; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\HttpFoundation\Response; -use Chill\MainBundle\Form\Type\Export\PickCenterType; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Security\Core\Role\Role; /** - * Test the export manager - * + * Test the export manager. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ExportManagerTest extends KernelTestCase { - use \Chill\MainBundle\Test\PrepareCenterTrait; use \Chill\MainBundle\Test\PrepareUserTrait; use \Chill\MainBundle\Test\PrepareScopeTrait; - - + /** - * - * @var Prophecy\Prophet + * @var Prophecy\Prophet */ private $prophet; - - - - - + public function setUp() { self::bootKernel(); - - $this->prophet = new \Prophecy\Prophet; + + $this->prophet = new \Prophecy\Prophet(); } - + public function tearDown() { $this->prophet->checkPredictions(); } - - /** - * Create an ExportManager where every element may be replaced by a double. - * - * If null is provided for an element, this is replaced by the equivalent - * from the container; if the user provided is null, this is replaced by the - * user 'center a_social' from database. - * - * @param \Psr\Log\LoggerInterface $logger - * @param \Doctrine\ORM\EntityManagerInterface $em - * @param \Symfony\Component\Security\Core\Authorization\AuthorizationChecker $authorizationChecker - * @param \Chill\MainBundle\Security\Authorization\AuthorizationHelper $authorizationHelper - * @param \Symfony\Component\Security\Core\User\UserInterface $user - * @return ExportManager - */ - protected function createExportManager( - \Psr\Log\LoggerInterface $logger = null, - \Doctrine\ORM\EntityManagerInterface $em = null, - \Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface $authorizationChecker = null, - \Chill\MainBundle\Security\Authorization\AuthorizationHelper $authorizationHelper = null, - \Symfony\Component\Security\Core\User\UserInterface $user = null - ) - { - $localUser = $user === NULL ? self::$container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => 'center a_social')) : - $user; - $token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($localUser, 'password', 'provider'); - $tokenStorage = new \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage(); - $tokenStorage->setToken($token); - - return new ExportManager( - $logger === NULL ? self::$container->get('logger') : $logger, - $em === NULL ? self::$container->get('doctrine.orm.entity_manager') : $em, - $authorizationChecker === NULL ? self::$container->get('security.authorization_checker') : $authorizationChecker, - $authorizationHelper === NULL ? self::$container->get('chill.main.security.authorization.helper') : $authorizationHelper, - $tokenStorage) - ; - } - - - public function testGetExportsWithoutGranting() - { - $exportManager = $this->createExportManager(); - - //create an export and add it to ExportManager - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $exportManager->addExport($export->reveal(), 'dummy'); - - $exports = iterator_to_array($exportManager->getExports(false)); - $this->assertGreaterThan(0, count($exports)); - $this->assertContains($export->reveal(), $exports); - $this->assertContains('dummy', array_keys($exports)); - } - - public function testGetExistingExportsTypes() + public function testAggregatorsApplyingOn() { - $exportManager = $this->createExportManager(); - - //create an export and add it to ExportManager - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $export->getType()->willReturn('my_type'); - $exportManager->addExport($export->reveal(), 'dummy'); - - $this->assertContains('my_type', $exportManager->getExistingExportsTypes()); - - } - - public function testGetExport() - { - $exportManager = $this->createExportManager(); - - //create an export and add it to ExportManager - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $exportManager->addExport($export->reveal(), 'dummy'); - - $obtained = $exportManager->getExport('dummy'); + $center = $this->prepareCenter(100, 'center'); + $centers = [$center]; + $user = $this->prepareUser([]); - $this->assertInstanceof(ExportInterface::class, $obtained); - } - - /** - * @expectedException \RuntimeException - */ - public function testGetExportNonExistant() - { - $exportManager = $this->createExportManager(); - - $exportManager->getExport('non existing'); - } - - public function testGetFilter() - { - $exportManager = $this->createExportManager(); - - //create a filter and add it to ExportManager - $filter = $this->prophet->prophesize(); - $filter->willImplement('Chill\MainBundle\Export\FilterInterface'); - $exportManager->addFilter($filter->reveal(), 'dummy'); - - $obtained = $exportManager->getFilter('dummy'); + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); - $this->assertInstanceof('Chill\MainBundle\Export\FilterInterface', $obtained); + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $exportFooBar = $this->prophet->prophesize(); + $exportFooBar->willImplement(ExportInterface::class); + $exportFooBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportFooBar->supportsModifiers()->willReturn(['foo', 'bar']); + + $aggregatorBar = $this->prophet->prophesize(); + $aggregatorBar->willImplement(AggregatorInterface::class); + $aggregatorBar->applyOn()->willReturn('bar'); + $aggregatorBar->addRole()->willReturn(null); + $exportManager->addAggregator($aggregatorBar->reveal(), 'bar'); + + $exportBar = $this->prophet->prophesize(); + $exportBar->willImplement(ExportInterface::class); + $exportBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportBar->supportsModifiers()->willReturn(['bar']); + + $aggregatorFoo = $this->prophet->prophesize(); + $aggregatorFoo->willImplement(AggregatorInterface::class); + $aggregatorFoo->applyOn()->willReturn('foo'); + $aggregatorFoo->addRole()->willReturn(null); + $exportManager->addAggregator($aggregatorFoo->reveal(), 'foo'); + + $exportFoo = $this->prophet->prophesize(); + $exportFoo->willImplement(ExportInterface::class); + $exportFoo->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportFoo->supportsModifiers()->willReturn(['foo']); + + $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFoo->reveal(), $centers)); + $this->assertEquals(1, count($obtained)); + $this->assertContains('foo', array_keys($obtained)); + + $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportBar->reveal(), $centers)); + $this->assertEquals(1, count($obtained)); + $this->assertContains('bar', array_keys($obtained)); + + $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFooBar->reveal(), $centers)); + $this->assertEquals(2, count($obtained)); + $this->assertContains('bar', array_keys($obtained)); + $this->assertContains('foo', array_keys($obtained)); + + // test with empty centers + $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFooBar->reveal(), [])); + $this->assertEquals(0, count($obtained)); } - - - /** - * @expectedException \RuntimeException - */ - public function testGetFilterNonExistant() + + public function testFiltersApplyingOn() { - $exportManager = $this->createExportManager(); - - $exportManager->getFilter('non existing'); - } - - public function testGetFilters() - { - $exportManager = $this->createExportManager(); - - //create three filters and add them to ExportManager - $filterFoo = $this->prophet->prophesize(); - $filterFoo->willImplement('Chill\MainBundle\Export\FilterInterface'); + $center = $this->prepareCenter(100, 'center'); + $centers = [$center]; + $user = $this->prepareUser([]); + + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); + + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $exportFooBar = $this->prophet->prophesize(); + $exportFooBar->willImplement(ExportInterface::class); + $exportFooBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportFooBar->supportsModifiers()->willReturn(['foo', 'bar']); + $filterBar = $this->prophet->prophesize(); - $filterBar->willImplement('Chill\MainBundle\Export\FilterInterface'); - $filterFooBar = $this->prophet->prophesize(); - $filterFooBar->willImplement('Chill\MainBundle\Export\FilterInterface'); - $exportManager->addFilter($filterFoo->reveal(), 'foo'); + $filterBar->willImplement(FilterInterface::class); + $filterBar->applyOn()->willReturn('bar'); + $filterBar->addRole()->willReturn(null); + $filterBar->describeAction(Argument::cetera())->willReturn('string'); $exportManager->addFilter($filterBar->reveal(), 'bar'); - $exportManager->addFilter($filterFooBar->reveal(), 'foobar'); - - $obtained = iterator_to_array($exportManager->getFilters(array('foo', 'bar'))); - $this->assertContains($filterBar->reveal(), $obtained); - $this->assertContains($filterFoo->reveal(), $obtained); - $this->assertNotContains($filterFooBar->reveal(), $obtained); + $exportBar = $this->prophet->prophesize(); + $exportBar->willImplement(ExportInterface::class); + $exportBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportBar->supportsModifiers()->willReturn(['bar']); + + $filterFoo = $this->prophet->prophesize(); + $filterFoo->willImplement(FilterInterface::class); + $filterFoo->applyOn()->willReturn('foo'); + $filterFoo->addRole()->willReturn(null); + $filterFoo->describeAction(Argument::cetera())->willReturn('string'); + $exportManager->addFilter($filterFoo->reveal(), 'foo'); + + $exportFoo = $this->prophet->prophesize(); + $exportFoo->willImplement(ExportInterface::class); + $exportFoo->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $exportFoo->supportsModifiers()->willReturn(['foo']); + + $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFoo->reveal(), $centers)); + $this->assertEquals(1, count($obtained)); + $this->assertContains('foo', array_keys($obtained)); + + $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportBar->reveal(), $centers)); + $this->assertEquals(1, count($obtained)); + $this->assertContains('bar', array_keys($obtained)); + + $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFooBar->reveal(), $centers)); + $this->assertEquals(2, count($obtained)); + $this->assertContains('bar', array_keys($obtained)); + $this->assertContains('foo', array_keys($obtained)); + + $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFooBar->reveal(), [])); + $this->assertEquals(0, count($obtained)); } - + + public function testFormattersByTypes() + { + $exportManager = $this->createExportManager(); + + //create a formatter + $formatterFoo = $this->prophet->prophesize(); + $formatterFoo->willImplement('Chill\MainBundle\Export\FormatterInterface'); + $formatterFoo->getType()->willReturn('foo'); + $formatterBar = $this->prophet->prophesize(); + $formatterBar->willImplement('Chill\MainBundle\Export\FormatterInterface'); + $formatterBar->getType()->willReturn('bar'); + $exportManager->addFormatter($formatterFoo->reveal(), 'foo'); + $exportManager->addFormatter($formatterBar->reveal(), 'bar'); + + $obtained = $exportManager->getFormattersByTypes(['foo']); + + $this->assertContains($formatterFoo->reveal(), $obtained); + $this->assertNotContains($formatterBar->reveal(), $obtained); + } + + /** + * Test the generation of an export. + */ + public function testGenerate() + { + $center = $this->prepareCenter(100, 'center'); + $user = $this->prepareUser([]); + + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); + + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $em = self::$container->get('doctrine.orm.entity_manager'); + $export->initiateQuery( + Argument::is(['foo']), + Argument::Type('array'), + Argument::is(['a' => 'b']) + ) + ->will(function () use ($em) { + $qb = $em->createQueryBuilder(); + + return $qb->addSelect('COUNT(user.id) as export') + ->from('ChillMainBundle:User', 'user'); + }); + //$export->initiateQuery()->shouldBeCalled(); + $export->supportsModifiers()->willReturn(['foo']); + $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + $export->getResult(Argument::Type(QueryBuilder::class), Argument::Type('array'))->willReturn([ + [ + 'aggregator' => 'cat a', + 'export' => 0, + ], + [ + 'aggregator' => 'cat b', + 'export' => 1, + ], + ]); + $export->getLabels( + Argument::is('export'), + Argument::is([0, 1]), + Argument::Type('array') + ) + ->willReturn(function ($value) { + switch ($value) { + case 0: + case 1: + return $value; + + case '_header': + return 'export'; + + default: throw new RuntimeException(sprintf('The value %s is not valid', $value)); + } + }); + + $export->getQueryKeys(Argument::Type('array'))->willReturn(['export']); + $export->getTitle()->willReturn('dummy title'); + $exportManager->addExport($export->reveal(), 'dummy'); + + $filter = $this->prophet->prophesize(); + $filter->willImplement(FilterInterface::class); + //$filter->alterQuery()->shouldBeCalled(); + $filter->alterQuery(Argument::Type(QueryBuilder::class), Argument::Type('array')) + ->willReturn(null); + $filter->addRole()->shouldBeCalled(); + //$filter->addRole()->shouldBeCalled(); + $filter->applyOn()->willReturn('foo'); + $filter->describeAction(Argument::cetera())->willReturn('filtered string'); + $exportManager->addFilter($filter->reveal(), 'filter_foo'); + + $aggregator = $this->prophet->prophesize(); + $aggregator->willImplement(AggregatorInterface::class); + $aggregator->applyOn()->willReturn('foo'); + $aggregator->alterQuery(Argument::Type(QueryBuilder::class), Argument::Type('array')) + ->willReturn(null); + //$aggregator->alterQuery()->shouldBeCalled(); + $aggregator->getQueryKeys(Argument::Type('array'))->willReturn(['aggregator']); + $aggregator->getLabels( + Argument::is('aggregator'), + Argument::is(['cat a', 'cat b']), + Argument::is([]) + ) + ->willReturn(function ($value) { + switch ($value) { + case '_header': return 'foo_header'; + + case 'cat a': return 'label cat a'; + + case 'cat b': return 'label cat b'; + + default: + throw new RuntimeException(sprintf('This value (%s) is not valid', $value)); + } + }); + $aggregator->addRole()->willReturn(null); + //$aggregator->addRole()->shouldBeCalled(); + $exportManager->addAggregator($aggregator->reveal(), 'aggregator_foo'); + + //add formatter interface + $formatter = new \Chill\MainBundle\Export\Formatter\SpreadSheetFormatter( + self::$container->get('translator'), + $exportManager + ); + $exportManager->addFormatter($formatter, 'spreadsheet'); + + //ob_start(); + $response = $exportManager->generate( + 'dummy', + [$center], + [ + ExportType::FILTER_KEY => [ + 'filter_foo' => [ + 'enabled' => true, + 'form' => [], + ], + ], + ExportType::AGGREGATOR_KEY => [ + 'aggregator_foo' => [ + 'enabled' => true, + 'form' => [], + ], + ], + ExportType::PICK_FORMATTER_KEY => [ + 'alias' => 'spreadsheet', + ], + ExportType::EXPORT_KEY => [ + 'a' => 'b', + ], + ], + [ + 'format' => 'csv', + 'aggregator_foo' => [ + 'order' => 1, + ], + ] + ); + //$content = ob_get_clean(); + $this->assertInstanceOf(Response::class, $response); + $expected = <<<'EOT' + "dummy title","" + "","" + "filtered string","" + "foo_header","_header" + "label cat a","" + "label cat b","1" + + EOT; + + $this->assertEquals($expected, $response->getContent()); + } + public function testGetAggregator() { $exportManager = $this->createExportManager(); - + //create a filter and add it to ExportManager $agg = $this->prophet->prophesize(); $agg->willImplement('Chill\MainBundle\Export\AggregatorInterface'); $exportManager->addAggregator($agg->reveal(), 'dummy'); - + $obtained = $exportManager->getAggregator('dummy'); $this->assertInstanceof('Chill\MainBundle\Export\AggregatorInterface', $obtained); } - - + /** * @expectedException \RuntimeException */ public function testGetAggregatorNonExistant() { $exportManager = $this->createExportManager(); - + $exportManager->getAggregator('non existing'); } - + public function testGetAggregators() { $exportManager = $this->createExportManager(); - + //create three filters and add them to ExportManager $aggFoo = $this->prophet->prophesize(); $aggFoo->willImplement('Chill\MainBundle\Export\AggregatorInterface'); @@ -248,425 +400,289 @@ class ExportManagerTest extends KernelTestCase $exportManager->addAggregator($aggFoo->reveal(), 'foo'); $exportManager->addAggregator($aggBar->reveal(), 'bar'); $exportManager->addAggregator($aggFooBar->reveal(), 'foobar'); - - $obtained = iterator_to_array($exportManager->getAggregators(array('foo', 'bar'))); + + $obtained = iterator_to_array($exportManager->getAggregators(['foo', 'bar'])); $this->assertContains($aggBar->reveal(), $obtained); $this->assertContains($aggFoo->reveal(), $obtained); $this->assertNotContains($aggFooBar->reveal(), $obtained); } - + + public function testGetExistingExportsTypes() + { + $exportManager = $this->createExportManager(); + + //create an export and add it to ExportManager + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $export->getType()->willReturn('my_type'); + $exportManager->addExport($export->reveal(), 'dummy'); + + $this->assertContains('my_type', $exportManager->getExistingExportsTypes()); + } + + public function testGetExport() + { + $exportManager = $this->createExportManager(); + + //create an export and add it to ExportManager + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $exportManager->addExport($export->reveal(), 'dummy'); + + $obtained = $exportManager->getExport('dummy'); + + $this->assertInstanceof(ExportInterface::class, $obtained); + } + + /** + * @expectedException \RuntimeException + */ + public function testGetExportNonExistant() + { + $exportManager = $this->createExportManager(); + + $exportManager->getExport('non existing'); + } + + public function testGetExportsWithoutGranting() + { + $exportManager = $this->createExportManager(); + + //create an export and add it to ExportManager + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $exportManager->addExport($export->reveal(), 'dummy'); + + $exports = iterator_to_array($exportManager->getExports(false)); + + $this->assertGreaterThan(0, count($exports)); + $this->assertContains($export->reveal(), $exports); + $this->assertContains('dummy', array_keys($exports)); + } + + public function testGetFilter() + { + $exportManager = $this->createExportManager(); + + //create a filter and add it to ExportManager + $filter = $this->prophet->prophesize(); + $filter->willImplement('Chill\MainBundle\Export\FilterInterface'); + $exportManager->addFilter($filter->reveal(), 'dummy'); + + $obtained = $exportManager->getFilter('dummy'); + + $this->assertInstanceof('Chill\MainBundle\Export\FilterInterface', $obtained); + } + + /** + * @expectedException \RuntimeException + */ + public function testGetFilterNonExistant() + { + $exportManager = $this->createExportManager(); + + $exportManager->getFilter('non existing'); + } + + public function testGetFilters() + { + $exportManager = $this->createExportManager(); + + //create three filters and add them to ExportManager + $filterFoo = $this->prophet->prophesize(); + $filterFoo->willImplement('Chill\MainBundle\Export\FilterInterface'); + $filterBar = $this->prophet->prophesize(); + $filterBar->willImplement('Chill\MainBundle\Export\FilterInterface'); + $filterFooBar = $this->prophet->prophesize(); + $filterFooBar->willImplement('Chill\MainBundle\Export\FilterInterface'); + $exportManager->addFilter($filterFoo->reveal(), 'foo'); + $exportManager->addFilter($filterBar->reveal(), 'bar'); + $exportManager->addFilter($filterFooBar->reveal(), 'foobar'); + + $obtained = iterator_to_array($exportManager->getFilters(['foo', 'bar'])); + + $this->assertContains($filterBar->reveal(), $obtained); + $this->assertContains($filterFoo->reveal(), $obtained); + $this->assertNotContains($filterFooBar->reveal(), $obtained); + } + public function testGetFormatter() { $exportManager = $this->createExportManager(); - + //create a formatter $formatter = $this->prophet->prophesize(); $formatter->willImplement('Chill\MainBundle\Export\FormatterInterface'); $exportManager->addFormatter($formatter->reveal(), 'dummy'); - + $obtained = $exportManager->getFormatter('dummy'); - + $this->assertInstanceOf('Chill\MainBundle\Export\FormatterInterface', $obtained); } - + + public function testIsGrantedForElementWithExportAndUserIsGranted() + { + $center = $this->prepareCenter(100, 'center A'); + $user = $this->prepareUser([]); + + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); + + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + + $result = $exportManager->isGrantedForElement($export->reveal(), null, [$center]); + + $this->assertTrue($result); + } + + public function testIsGrantedForElementWithExportAndUserIsGrantedNotForAllCenters() + { + $center = $this->prepareCenter(100, 'center A'); + $centerB = $this->prepareCenter(102, 'center B'); + $user = $this->prepareUser([]); + + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $centerB) + ->willReturn(false); + + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + + $result = $exportManager->isGrantedForElement($export->reveal(), null, [$center, $centerB]); + + $this->assertFalse($result); + } + + public function testIsGrantedForElementWithExportEmptyCenters() + { + $user = $this->prepareUser([]); + + $exportManager = $this->createExportManager( + null, + null, + null, + null, + $user + ); + + $export = $this->prophet->prophesize(); + $export->willImplement(\Chill\MainBundle\Export\ExportInterface::class); + $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + + $result = $exportManager->isGrantedForElement($export->reveal(), null, []); + + $this->assertFalse($result); + } + + public function testIsGrantedForElementWithModifierFallbackToExport() + { + $center = $this->prepareCenter(100, 'center A'); + $centerB = $this->prepareCenter(102, 'center B'); + $user = $this->prepareUser([]); + + $authorizationChecker = $this->prophet->prophesize(); + $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) + ->willReturn(true); + $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $centerB) + ->willReturn(false); + + $exportManager = $this->createExportManager( + null, + null, + $authorizationChecker->reveal(), + null, + $user + ); + + $modifier = $this->prophet->prophesize(); + $modifier->willImplement(\Chill\MainBundle\Export\ModifierInterface::class); + $modifier->addRole()->willReturn(null); + + $export = $this->prophet->prophesize(); + $export->willImplement(ExportInterface::class); + $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); + + $result = $exportManager->isGrantedForElement( + $modifier->reveal(), + $export->reveal(), + [$center, $centerB] + ); + + $this->assertFalse($result); + } + /** * @expectedException \RuntimeException */ public function testNonExistingFormatter() { $exportManager = $this->createExportManager(); - + $exportManager->getFormatter('non existing'); } - - public function testFormattersByTypes() - { - $exportManager = $this->createExportManager(); - - //create a formatter - $formatterFoo = $this->prophet->prophesize(); - $formatterFoo->willImplement('Chill\MainBundle\Export\FormatterInterface'); - $formatterFoo->getType()->willReturn('foo'); - $formatterBar = $this->prophet->prophesize(); - $formatterBar->willImplement('Chill\MainBundle\Export\FormatterInterface'); - $formatterBar->getType()->willReturn('bar'); - $exportManager->addFormatter($formatterFoo->reveal(), 'foo'); - $exportManager->addFormatter($formatterBar->reveal(), 'bar'); - - $obtained = $exportManager->getFormattersByTypes(array('foo')); - - $this->assertContains($formatterFoo->reveal(), $obtained); - $this->assertNotContains($formatterBar->reveal(), $obtained); - } - - public function testIsGrantedForElementWithExportAndUserIsGranted() - { - $center = $this->prepareCenter(100, 'center A'); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(True); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - - $result = $exportManager->isGrantedForElement($export->reveal(), null, array($center)); - - $this->assertTrue($result); - - } - - public function testIsGrantedForElementWithExportAndUserIsGrantedNotForAllCenters() - { - $center = $this->prepareCenter(100, 'center A'); - $centerB = $this->prepareCenter(102, 'center B'); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(true); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $centerB) - ->willReturn(false); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - - $result = $exportManager->isGrantedForElement($export->reveal(), null, array($center, $centerB)); - - $this->assertFalse($result); - - } - - public function testIsGrantedForElementWithExportEmptyCenters() - { - $user = $this->prepareUser(array()); - - $exportManager = $this->createExportManager(null, null, - null, null, $user); - - $export = $this->prophet->prophesize(); - $export->willImplement(\Chill\MainBundle\Export\ExportInterface::class); - $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - - $result = $exportManager->isGrantedForElement($export->reveal(), null, array()); - - $this->assertFalse($result); - - } - - public function testIsGrantedForElementWithModifierFallbackToExport() - { - $center = $this->prepareCenter(100, 'center A'); - $centerB = $this->prepareCenter(102, 'center B'); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(true); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $centerB) - ->willReturn(false); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $modifier = $this->prophet->prophesize(); - $modifier->willImplement(\Chill\MainBundle\Export\ModifierInterface::class); - $modifier->addRole()->willReturn(NULL); - - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - - $result = $exportManager->isGrantedForElement($modifier->reveal(), - $export->reveal(), array($center, $centerB)); - - $this->assertFalse($result); - - } - - public function testAggregatorsApplyingOn() - { - $center = $this->prepareCenter(100, 'center'); - $centers = array($center); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(true); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $exportFooBar = $this->prophet->prophesize(); - $exportFooBar->willImplement(ExportInterface::class); - $exportFooBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportFooBar->supportsModifiers()->willReturn(array('foo', 'bar')); - - $aggregatorBar = $this->prophet->prophesize(); - $aggregatorBar->willImplement(AggregatorInterface::class); - $aggregatorBar->applyOn()->willReturn('bar'); - $aggregatorBar->addRole()->willReturn(null); - $exportManager->addAggregator($aggregatorBar->reveal(), 'bar'); - - $exportBar = $this->prophet->prophesize(); - $exportBar->willImplement(ExportInterface::class); - $exportBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportBar->supportsModifiers()->willReturn(array('bar')); - - $aggregatorFoo = $this->prophet->prophesize(); - $aggregatorFoo->willImplement(AggregatorInterface::class); - $aggregatorFoo->applyOn()->willReturn('foo'); - $aggregatorFoo->addRole()->willReturn(null); - $exportManager->addAggregator($aggregatorFoo->reveal(), 'foo'); - - $exportFoo = $this->prophet->prophesize(); - $exportFoo->willImplement(ExportInterface::class); - $exportFoo->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportFoo->supportsModifiers()->willReturn(array('foo')); - - $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFoo->reveal(), $centers)); - $this->assertEquals(1, count($obtained)); - $this->assertContains('foo', array_keys($obtained)); - - $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportBar->reveal(), $centers)); - $this->assertEquals(1, count($obtained)); - $this->assertContains('bar', array_keys($obtained)); - - $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFooBar->reveal(), $centers)); - $this->assertEquals(2, count($obtained)); - $this->assertContains('bar', array_keys($obtained)); - $this->assertContains('foo', array_keys($obtained)); - - // test with empty centers - $obtained = iterator_to_array($exportManager->getAggregatorsApplyingOn($exportFooBar->reveal(), array())); - $this->assertEquals(0, count($obtained)); - - } - - public function testFiltersApplyingOn() - { - $center = $this->prepareCenter(100, 'center'); - $centers = array($center); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(true); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $exportFooBar = $this->prophet->prophesize(); - $exportFooBar->willImplement(ExportInterface::class); - $exportFooBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportFooBar->supportsModifiers()->willReturn(array('foo', 'bar')); - - $filterBar = $this->prophet->prophesize(); - $filterBar->willImplement(FilterInterface::class); - $filterBar->applyOn()->willReturn('bar'); - $filterBar->addRole()->willReturn(null); - $filterBar->describeAction(Argument::cetera())->willReturn('string'); - $exportManager->addFilter($filterBar->reveal(), 'bar'); - - $exportBar = $this->prophet->prophesize(); - $exportBar->willImplement(ExportInterface::class); - $exportBar->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportBar->supportsModifiers()->willReturn(array('bar')); - - $filterFoo = $this->prophet->prophesize(); - $filterFoo->willImplement(FilterInterface::class); - $filterFoo->applyOn()->willReturn('foo'); - $filterFoo->addRole()->willReturn(null); - $filterFoo->describeAction(Argument::cetera())->willReturn('string'); - $exportManager->addFilter($filterFoo->reveal(), 'foo'); - - $exportFoo = $this->prophet->prophesize(); - $exportFoo->willImplement(ExportInterface::class); - $exportFoo->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $exportFoo->supportsModifiers()->willReturn(array('foo')); - - - $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFoo->reveal(), $centers)); - $this->assertEquals(1, count($obtained)); - $this->assertContains('foo', array_keys($obtained)); - - $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportBar->reveal(), $centers)); - $this->assertEquals(1, count($obtained)); - $this->assertContains('bar', array_keys($obtained)); - - $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFooBar->reveal(), $centers)); - $this->assertEquals(2, count($obtained)); - $this->assertContains('bar', array_keys($obtained)); - $this->assertContains('foo', array_keys($obtained)); - - $obtained = iterator_to_array($exportManager->getFiltersApplyingOn($exportFooBar->reveal(), array())); - $this->assertEquals(0, count($obtained)); - } - /** - * Test the generation of an export + * Create an ExportManager where every element may be replaced by a double. + * + * If null is provided for an element, this is replaced by the equivalent + * from the container; if the user provided is null, this is replaced by the + * user 'center a_social' from database. + * + * @param \Psr\Log\LoggerInterface $logger + * @param \Doctrine\ORM\EntityManagerInterface $em + * @param \Symfony\Component\Security\Core\Authorization\AuthorizationChecker $authorizationChecker + * @param \Chill\MainBundle\Security\Authorization\AuthorizationHelper $authorizationHelper + * @param \Symfony\Component\Security\Core\User\UserInterface $user + * + * @return ExportManager */ - public function testGenerate() - { - $center = $this->prepareCenter(100, 'center'); - $user = $this->prepareUser(array()); - - $authorizationChecker = $this->prophet->prophesize(); - $authorizationChecker->willImplement(AuthorizationCheckerInterface::class); - $authorizationChecker->isGranted('CHILL_STAT_DUMMY', $center) - ->willReturn(true); - - $exportManager = $this->createExportManager(null, null, - $authorizationChecker->reveal(), null, $user); - - $export = $this->prophet->prophesize(); - $export->willImplement(ExportInterface::class); - $em = self::$container->get('doctrine.orm.entity_manager'); - $export->initiateQuery( - Argument::is(array('foo')), - Argument::Type('array'), - Argument::is(array('a' => 'b')) - ) - ->will(function () use ($em) { - $qb = $em->createQueryBuilder(); - return $qb->addSelect('COUNT(user.id) as export') - ->from('ChillMainBundle:User', 'user'); - - }); - //$export->initiateQuery()->shouldBeCalled(); - $export->supportsModifiers()->willReturn(array('foo')); - $export->requiredRole()->willReturn(new Role('CHILL_STAT_DUMMY')); - $export->getResult(Argument::Type(QueryBuilder::class), Argument::Type('array'))->willReturn(array( - array( - 'aggregator' => 'cat a', - 'export' => 0, - ), - array( - 'aggregator' => 'cat b', - 'export' => 1 - ) - )); - $export->getLabels( - Argument::is('export'), - Argument::is(array(0, 1)), - Argument::Type('array') - ) - ->willReturn(function($value) { - switch($value) { - case 0: - case 1: - return $value; - case '_header': - return 'export'; - default: throw new \RuntimeException(sprintf("The value %s is not valid", $value)); - } - }); - - $export->getQueryKeys(Argument::Type('array'))->willReturn(array('export')); - $export->getTitle()->willReturn('dummy title'); - $exportManager->addExport($export->reveal(), 'dummy'); - - $filter = $this->prophet->prophesize(); - $filter->willImplement(FilterInterface::class); - //$filter->alterQuery()->shouldBeCalled(); - $filter->alterQuery(Argument::Type(QueryBuilder::class), Argument::Type('array')) - ->willReturn(null); - $filter->addRole()->shouldBeCalled(); - //$filter->addRole()->shouldBeCalled(); - $filter->applyOn()->willReturn('foo'); - $filter->describeAction(Argument::cetera())->willReturn('filtered string'); - $exportManager->addFilter($filter->reveal(), 'filter_foo'); - - $aggregator = $this->prophet->prophesize(); - $aggregator->willImplement(AggregatorInterface::class); - $aggregator->applyOn()->willReturn('foo'); - $aggregator->alterQuery(Argument::Type(QueryBuilder::class), Argument::Type('array')) - ->willReturn(null); - //$aggregator->alterQuery()->shouldBeCalled(); - $aggregator->getQueryKeys(Argument::Type('array'))->willReturn(array('aggregator')); - $aggregator->getLabels( - Argument::is('aggregator'), - Argument::is(array('cat a', 'cat b')), - Argument::is(array()) - ) - ->willReturn(function($value) { - switch ($value) { - case '_header': return 'foo_header'; - case 'cat a' : return 'label cat a'; - case 'cat b' : return 'label cat b'; - default: - throw new \RuntimeException(sprintf("This value (%s) is not valid", $value)); - } - }); - $aggregator->addRole()->willReturn(null); - //$aggregator->addRole()->shouldBeCalled(); - $exportManager->addAggregator($aggregator->reveal(), 'aggregator_foo'); - - //add formatter interface - $formatter = new \Chill\MainBundle\Export\Formatter\SpreadSheetFormatter( - self::$container->get('translator'), $exportManager); - $exportManager->addFormatter($formatter, 'spreadsheet'); - - //ob_start(); - $response = $exportManager->generate( - 'dummy', - array($center), - array( - ExportType::FILTER_KEY => array( - 'filter_foo' => array( - 'enabled' => true, - 'form' => array() - ) - ), - ExportType::AGGREGATOR_KEY => array( - 'aggregator_foo' => array( - 'enabled' => true, - 'form' => array() - ) - ), - ExportType::PICK_FORMATTER_KEY => array( - 'alias' => 'spreadsheet' - ), - ExportType::EXPORT_KEY => array( - 'a' => 'b' - ) - ), - array( - 'format' => 'csv', - 'aggregator_foo' => array( - 'order' => 1 - ) - ) - ); - //$content = ob_get_clean(); - $this->assertInstanceOf(Response::class, $response); - $expected = <<get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:User') + ->findOneBy(['username' => 'center a_social']) : + $user; + $token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($localUser, 'password', 'provider'); + $tokenStorage = new \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage(); + $tokenStorage->setToken($token); -EOT; - - $this->assertEquals($expected, $response->getContent()); + return new ExportManager( + null === $logger ? self::$container->get('logger') : $logger, + null === $em ? self::$container->get('doctrine.orm.entity_manager') : $em, + null === $authorizationChecker ? self::$container->get('security.authorization_checker') : $authorizationChecker, + null === $authorizationHelper ? self::$container->get('chill.main.security.authorization.helper') : $authorizationHelper, + $tokenStorage + ); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Form/Type/CenterTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/CenterTypeTest.php index 48b96375e..14d154848 100644 --- a/src/Bundle/ChillMainBundle/Tests/Form/Type/CenterTypeTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/CenterTypeTest.php @@ -1,83 +1,28 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Form\Type; -use Symfony\Component\Form\Test\TypeTestCase; -use Chill\MainBundle\Form\Type\CenterType; -use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\GroupCenter; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Chill\MainBundle\Entity\User; use Symfony\Bridge\Doctrine\Form\Type\EntityType; - +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\Test\TypeTestCase; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class CenterTypeTest extends TypeTestCase { /** - * Test that a user which can reach only one center - * render as an hidden field - */ - public function testUserCanReachSingleCenter() - { - //prepare user - $center = $this->prepareCenter(1, 'center'); - $groupCenter = (new GroupCenter()) - ->setCenter($center) - ; - $user = (new User()) - ->addGroupCenter($groupCenter); - - $type = $this->prepareType($user); - - $this->assertEquals(HiddenType::class, $type->getParent()); - } - - /** - * Test that a user which can reach only one center - * render as an hidden field - */ - public function testUserCanReachMultipleSameCenter() - { - //prepare user - $center = $this->prepareCenter(1, 'center'); - $groupCenterA = (new GroupCenter()) - ->setCenter($center) - ; - $groupCenterB = (new GroupCenter()) - ->setCenter($center) - ; - $user = (new User()) - ->addGroupCenter($groupCenterA) - ->addGroupCenter($groupCenterB); - - $type = $this->prepareType($user); - - $this->assertEquals(HiddenType::class, $type->getParent()); - } - - /** - * Test that a user which can reach multiple center + * Test that a user which can reach multiple center * make CenterType render as "entity" type. */ public function testUserCanReachMultipleCenters() @@ -86,70 +31,106 @@ class CenterTypeTest extends TypeTestCase $centerA = $this->prepareCenter(1, 'centerA'); $centerB = $this->prepareCenter(2, 'centerB'); $groupCenterA = (new GroupCenter()) - ->setCenter($centerA) - ; + ->setCenter($centerA); $groupCenterB = (new GroupCenter()) - ->setCenter($centerB) - ; + ->setCenter($centerB); $user = (new User()) - ->addGroupCenter($groupCenterA) - ->addGroupCenter($groupCenterB) - ; - + ->addGroupCenter($groupCenterA) + ->addGroupCenter($groupCenterB); + $type = $this->prepareType($user); - + $this->assertEquals(EntityType::class, $type->getParent()); } - + /** - * prepare a mocked center, with and id and name given - * + * Test that a user which can reach only one center + * render as an hidden field. + */ + public function testUserCanReachMultipleSameCenter() + { + //prepare user + $center = $this->prepareCenter(1, 'center'); + $groupCenterA = (new GroupCenter()) + ->setCenter($center); + $groupCenterB = (new GroupCenter()) + ->setCenter($center); + $user = (new User()) + ->addGroupCenter($groupCenterA) + ->addGroupCenter($groupCenterB); + + $type = $this->prepareType($user); + + $this->assertEquals(HiddenType::class, $type->getParent()); + } + + /** + * Test that a user which can reach only one center + * render as an hidden field. + */ + public function testUserCanReachSingleCenter() + { + //prepare user + $center = $this->prepareCenter(1, 'center'); + $groupCenter = (new GroupCenter()) + ->setCenter($center); + $user = (new User()) + ->addGroupCenter($groupCenter); + + $type = $this->prepareType($user); + + $this->assertEquals(HiddenType::class, $type->getParent()); + } + + /** + * prepare a mocked center, with and id and name given. + * * @param int $id * @param string $name - * @return \Chill\MainBundle\Entity\Center + * + * @return \Chill\MainBundle\Entity\Center */ private function prepareCenter($id, $name) { - $prophet = new \Prophecy\Prophet; - + $prophet = new \Prophecy\Prophet(); + $prophecyCenter = $prophet->prophesize(); $prophecyCenter->willExtend('\Chill\MainBundle\Entity\Center'); $prophecyCenter->getId()->willReturn($id); $prophecyCenter->getName()->willReturn($name); - + return $prophecyCenter->reveal(); } - - + /** - * prepare the type with mocked center transformer and token storage - * + * prepare the type with mocked center transformer and token storage. + * * @param User $user the user for wich the form will be prepared + * * @return CenterType */ private function prepareType(User $user) { - $prophet = new \Prophecy\Prophet; - + $prophet = new \Prophecy\Prophet(); + //create a center transformer $centerTransformerProphecy = $prophet->prophesize(); $centerTransformerProphecy - ->willExtend('Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer'); + ->willExtend('Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer'); $transformer = $centerTransformerProphecy->reveal(); - + $tokenProphecy = $prophet->prophesize(); $tokenProphecy - ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); $tokenProphecy->getUser()->willReturn($user); $token = $tokenProphecy->reveal(); - + $tokenStorageProphecy = $prophet->prophesize(); $tokenStorageProphecy - ->willExtend('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage'); + ->willExtend('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage'); $tokenStorageProphecy->getToken()->willReturn($token); $tokenStorage = $tokenStorageProphecy->reveal(); - + return new CenterType($tokenStorage, $transformer); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Pagination/PageTest.php b/src/Bundle/ChillMainBundle/Tests/Pagination/PageTest.php index 3f0dd2367..70568c8ac 100644 --- a/src/Bundle/ChillMainBundle/Tests/Pagination/PageTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Pagination/PageTest.php @@ -1,148 +1,135 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Pagination; +use Chill\MainBundle\Pagination\Page; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Chill\MainBundle\Pagination\Page; /** - * Test the Page class + * Test the Page class. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class PageTest extends KernelTestCase { protected $paginator; - + protected $prophet; - - public function setUp() { - $this->prophet = new \Prophecy\Prophet; - - + + public function setUp() + { + $this->prophet = new \Prophecy\Prophet(); } - + /** - * - * @param int $maxResult - * @param int $itemPerPage - * @param string $route - * @param array $routeParameters - * @return Page - */ - protected function generatePage( - $number = 1, - $itemPerPage = 10, - $route = 'route', - array $routeParameters = array(), - $totalItems = 100 - ) { - $urlGenerator = $this->prophet->prophesize(); - $urlGenerator->willImplement(UrlGeneratorInterface::class); - - return new Page( - $number, - $itemPerPage, - $urlGenerator->reveal(), - $route, - $routeParameters, - $totalItems - ); - } - - public function testPageNumber() { - $page = $this->generatePage(1); - - $this->assertEquals(1, $page->getNumber()); - } - - /** - * return a set of element to testGetFirstItemNumber - * - * the set contains : + * return a set of element to testGetFirstItemNumber. + * + * the set contains : * - the page number ; * - the number of item per page ; * - the expected first item number - * + * * @return array */ - public function generateGetFirstItemNumber() { - return array( - [1, 10, 0], - [2, 10, 10] - ); + public function generateGetFirstItemNumber() + { + return [ + [1, 10, 0], + [2, 10, 10], + ]; } - + + /** + * return a set of element to testGetLastItemNumber. + * + * the set contains : + * - the page number ; + * - the number of item per page ; + * - the expected last item number + * + * @return array + */ + public function generateGetLastItemNumber() + { + return [ + [1, 10, 9], + [2, 10, 19], + ]; + } + /** - * * @param int $number * @param int $itemPerPage * @param int $expectedItemPerPage * @dataProvider generateGetFirstItemNumber */ public function testGetFirstItemNumber( - $number, - $itemPerPage, - $expectedItemPerPage + $number, + $itemPerPage, + $expectedItemPerPage ) { $page = $this->generatePage($number, $itemPerPage); - + $this->assertEquals($expectedItemPerPage, $page->getFirstItemNumber()); } - + /** - * return a set of element to testGetLastItemNumber - * - * the set contains : - * - the page number ; - * - the number of item per page ; - * - the expected last item number - * - * @return array - */ - public function generateGetLastItemNumber() { - return array( - [1, 10, 9], - [2, 10, 19] - ); - } - - /** - * * @param int $number * @param int $itemPerPage * @param int $expectedItemPerPage * @dataProvider generateGetLastItemNumber */ public function testGetLastItemNumber( - $number, - $itemPerPage, - $expectedItemPerPage + $number, + $itemPerPage, + $expectedItemPerPage ) { $page = $this->generatePage($number, $itemPerPage); - + $this->assertEquals($expectedItemPerPage, $page->getLastItemNumber()); } - - + + public function testPageNumber() + { + $page = $this->generatePage(1); + + $this->assertEquals(1, $page->getNumber()); + } + + /** + * @param int $itemPerPage + * @param string $route + * @param mixed $number + * @param mixed $totalItems + * + * @return Page + */ + protected function generatePage( + $number = 1, + $itemPerPage = 10, + $route = 'route', + array $routeParameters = [], + $totalItems = 100 + ) { + $urlGenerator = $this->prophet->prophesize(); + $urlGenerator->willImplement(UrlGeneratorInterface::class); + + return new Page( + $number, + $itemPerPage, + $urlGenerator->reveal(), + $route, + $routeParameters, + $totalItems + ); + } } diff --git a/src/Bundle/ChillMainBundle/Tests/Pagination/PaginatorTest.php b/src/Bundle/ChillMainBundle/Tests/Pagination/PaginatorTest.php index b1a234b94..9d35fc004 100644 --- a/src/Bundle/ChillMainBundle/Tests/Pagination/PaginatorTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Pagination/PaginatorTest.php @@ -1,133 +1,110 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Pagination; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Chill\MainBundle\Pagination\Paginator; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** - * Test the paginator class + * Test the paginator class. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class PaginatorTest extends KernelTestCase { protected $paginator; - + protected $prophet; - - public function setUp() + + public function setUp() { - $this->prophet = new \Prophecy\Prophet; + $this->prophet = new \Prophecy\Prophet(); } - - /** - * - * @param int $maxResult - * @param int $itemPerPage - * @param string $route - * @param array $routeParameters - * @return Paginator - */ - protected function generatePaginator( - $totalItems, - $itemPerPage, - $currentPageNumber = 1, - $route = '', - array $routeParameters = array() - ) { - $urlGenerator = $this->prophet->prophesize(); - $urlGenerator->willImplement(UrlGeneratorInterface::class); - - return new Paginator( - $totalItems, - $itemPerPage, - $currentPageNumber, - $route, - $routeParameters, - $urlGenerator->reveal(), - 'page', - 'item_per_page' - ); - } - - /** - * generate a set of pages with different maxItem, itemPerPage, and - * expected page number - * - * @return array - */ - public function generatePageNumber() - { - return array( - [12, 10, 2], - [20, 10, 2], - [21, 10, 3], - [19, 10, 2], - [1, 10, 1], - [0, 10, 1], - [10, 10, 1] - ); - } - - /** - * Test that the countPages method (and his alias `count`) return - * valid results. - * - * @param int $totalItems - * @param int $itemPerPage - * @param int $expectedPageNumber - * @dataProvider generatePageNumber - */ - public function testPageNumber($totalItems, $itemPerPage, $expectedPageNumber) - { - $paginator = $this->generatePaginator($totalItems, $itemPerPage); - - $this->assertEquals($expectedPageNumber, $paginator->countPages()); - $this->assertEquals($expectedPageNumber, count($paginator)); - } - + /** * generate an array with a set of page with : * - total items ; * - item per page ; * - current page number ; - * - expected hasNextPage result - * + * - expected hasNextPage result. + * * @return array */ - public function generateHasNextPage() + public function generateHasNextPage() { - return array( - [10, 10, 1, false], - [20, 10, 1, true], - [12, 10, 1, true], - [12, 10, 2, false] - ); + return [ + [10, 10, 1, false], + [20, 10, 1, true], + [12, 10, 1, true], + [12, 10, 2, false], + ]; } - + + public function generateHasPage() + { + return [ + [10, 10, -1, false], + [12, 10, 1, true], + [12, 10, 2, true], + [12, 10, 3, false], + ]; + } + + /** + * generate an array with a set of page with : + * - total items ; + * - item per page ; + * - current page number ; + * - expected hasPreviousPage result. + * + * @return array + */ + public function generateHasPreviousPage() + { + return [ + [10, 10, 1, false], + [20, 10, 1, false], + [12, 10, 1, false], + [12, 10, 2, true], + ]; + } + + /** + * generate a set of pages with different maxItem, itemPerPage, and + * expected page number. + * + * @return array + */ + public function generatePageNumber() + { + return [ + [12, 10, 2], + [20, 10, 2], + [21, 10, 3], + [19, 10, 2], + [1, 10, 1], + [0, 10, 1], + [10, 10, 1], + ]; + } + + public function testGetPage() + { + $paginator = $this->generatePaginator(105, 10); + + $this->assertEquals(5, $paginator->getPage(5)->getNumber()); + } + /** - * * @param int $totalItems * @param int $itemPerPage * @param int $currentPage @@ -135,103 +112,122 @@ class PaginatorTest extends KernelTestCase * @dataProvider generateHasNextPage */ public function testHasNextPage( - $totalItems, - $itemPerPage, - $currentPage, - $expectedHasNextPage + $totalItems, + $itemPerPage, + $currentPage, + $expectedHasNextPage ) { $paginator = $this->generatePaginator($totalItems, $itemPerPage, $currentPage); - + $this->assertEquals($expectedHasNextPage, $paginator->hasNextPage()); } - + /** - * generate an array with a set of page with : - * - total items ; - * - item per page ; - * - current page number ; - * - expected hasPreviousPage result - * - * @return array - */ - public function generateHasPreviousPage() - { - return array( - [10, 10, 1, false], - [20, 10, 1, false], - [12, 10, 1, false], - [12, 10, 2, true], - ); - } - - /** - * - * @param int $totalItems - * @param int $itemPerPage - * @param int $currentPage - * @param bool $expectedHasPreviousPage - * @dataProvider generateHasPreviousPage - */ - public function testHasPreviousPage( - $totalItems, - $itemPerPage, - $currentPage, - $expectedHasNextPage - ) { - $paginator = $this->generatePaginator($totalItems, $itemPerPage, $currentPage); - - $this->assertEquals($expectedHasNextPage, $paginator->hasPreviousPage()); - } - - public function generateHasPage() - { - return array( - [10, 10, -1, false], - [12, 10, 1, true], - [12, 10, 2, true], - [12, 10, 3, false] - ); - } - - /** - * test the HasPage function - * - * + * test the HasPage function. + * * @param int $totalItems * @param int $itemPerpage * @param int $pageNumber * @param bool $expectedHasPage * @dataProvider generateHasPage */ - public function testHasPage($totalItems, $itemPerpage, $pageNumber, - $expectedHasPage) - { + public function testHasPage( + $totalItems, + $itemPerpage, + $pageNumber, + $expectedHasPage + ) { $paginator = $this->generatePaginator($totalItems, $itemPerpage); - + $this->assertEquals($expectedHasPage, $paginator->hasPage($pageNumber)); } - - public function testGetPage() - { - $paginator = $this->generatePaginator(105, 10); - - $this->assertEquals(5, $paginator->getPage(5)->getNumber()); + + /** + * @param int $totalItems + * @param int $itemPerPage + * @param int $currentPage + * @param mixed $expectedHasNextPage + * @dataProvider generateHasPreviousPage + */ + public function testHasPreviousPage( + $totalItems, + $itemPerPage, + $currentPage, + $expectedHasNextPage + ) { + $paginator = $this->generatePaginator($totalItems, $itemPerPage, $currentPage); + + $this->assertEquals($expectedHasNextPage, $paginator->hasPreviousPage()); } - + + /** + * Test that the countPages method (and his alias `count`) return + * valid results. + * + * @param int $totalItems + * @param int $itemPerPage + * @param int $expectedPageNumber + * @dataProvider generatePageNumber + */ + public function testPageNumber($totalItems, $itemPerPage, $expectedPageNumber) + { + $paginator = $this->generatePaginator($totalItems, $itemPerPage); + + $this->assertEquals($expectedPageNumber, $paginator->countPages()); + $this->assertEquals($expectedPageNumber, count($paginator)); + } + public function testPagesGenerator() { $paginator = $this->generatePaginator(105, 10); - + $generator = $paginator->getPagesGenerator(); - + $i = 1; - foreach($generator as $page) { - $this->assertEquals($i, $page->getNumber(), - "assert that the current page number is $i"); - $i++; + + foreach ($generator as $page) { + $this->assertEquals( + $i, + $page->getNumber(), + "assert that the current page number is {$i}" + ); + ++$i; } - - $this->assertEquals(11, $page->getNumber(), - "assert that the last page number is 11"); + + $this->assertEquals( + 11, + $page->getNumber(), + 'assert that the last page number is 11' + ); + } + + /** + * @param int $itemPerPage + * @param string $route + * @param mixed $totalItems + * @param mixed $currentPageNumber + * + * @return Paginator + */ + protected function generatePaginator( + $totalItems, + $itemPerPage, + $currentPageNumber = 1, + $route = '', + array $routeParameters = [] + ) { + $urlGenerator = $this->prophet->prophesize(); + $urlGenerator->willImplement(UrlGeneratorInterface::class); + + return new Paginator( + $totalItems, + $itemPerPage, + $currentPageNumber, + $route, + $routeParameters, + $urlGenerator->reveal(), + 'page', + 'item_per_page' + ); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Routing/Loader/RouteLoaderTest.php b/src/Bundle/ChillMainBundle/Tests/Routing/Loader/RouteLoaderTest.php index 359c47a7b..ba400dfdf 100644 --- a/src/Bundle/ChillMainBundle/Tests/Routing/Loader/RouteLoaderTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Routing/Loader/RouteLoaderTest.php @@ -1,52 +1,39 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Routing\Loader; -use Chill\MainBundle\Routing\Loader\ChillRoutesLoader; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; - /** - * Test the route loader + * Test the route loader. * - * @author Julien Fastré + * @internal + * @coversNothing */ class RouteLoaderTest extends KernelTestCase { private $router; - + public function setUp() { static::bootKernel(); $this->router = static::$kernel->getContainer()->get('router'); } - + /** - * Test that the route loader loads at least homepage + * Test that the route loader loads at least homepage. */ public function testRouteFromMainBundleAreLoaded() { $homepage = $this->router->getRouteCollection()->get('chill_main_homepage'); - + $this->assertNotNull($homepage); } - } diff --git a/src/Bundle/ChillMainBundle/Tests/Search/AbstractSearchTest.php b/src/Bundle/ChillMainBundle/Tests/Search/AbstractSearchTest.php index c0f1827fb..a39dc0738 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/AbstractSearchTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/AbstractSearchTest.php @@ -1,29 +1,19 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Search; /** - * Description of AbstractSearch + * Description of AbstractSearch. * - * @author Julien Fastré + * @internal + * @coversNothing */ class AbstractSearchTest extends \PHPUnit\Framework\TestCase { @@ -31,22 +21,21 @@ class AbstractSearchTest extends \PHPUnit\Framework\TestCase * @var \Chill\MainBundle\Search\AbstractSearch */ private $stub; - + public function setUp() { $this->stub = $this->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); } - + public function testParseDateRegular() { - $date = $this->stub->parseDate('2014-05-01'); $this->assertEquals('2014', $date->format('Y')); $this->assertEquals('05', $date->format('m')); $this->assertEquals('01', $date->format('d')); } - + public function testRecompose() { $this->markTestSkipped(); diff --git a/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php b/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php index 554b67b9a..94658f68a 100644 --- a/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Search/SearchProviderTest.php @@ -1,197 +1,150 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Test\Search; -use Chill\MainBundle\Search\SearchProvider; use Chill\MainBundle\Search\SearchInterface; +use Chill\MainBundle\Search\SearchProvider; use PHPUnit\Framework\TestCase; - +/** + * @internal + * @coversNothing + */ class SearchProviderTest extends TestCase { - /** - * - * @var SearchProvider + * @var SearchProvider */ private $search; - + public function setUp() { $this->search = new SearchProvider(); - + //add a default service $this->addSearchService( - $this->createDefaultSearchService('I am default', 10), 'default' - ); + $this->createDefaultSearchService('I am default', 10), + 'default' + ); //add a domain service $this->addSearchService( - $this->createNonDefaultDomainSearchService('I am domain bar', 20, FALSE), 'bar' - ); + $this->createNonDefaultDomainSearchService('I am domain bar', 20, false), + 'bar' + ); } - + + public function testAccentued() + { + //$this->markTestSkipped('accentued characters must be implemented'); + + $terms = $this->p('manço bélier aztèque à saloù ê'); + + $this->assertEquals([ + '_domain' => null, + '_default' => 'manco belier azteque a salou e', + ], $terms); + } + + public function testAccentuedCapitals() + { + //$this->markTestSkipped('accentued characters must be implemented'); + + $terms = $this->p('MANÉÀ oÛ lÎ À'); + + $this->assertEquals([ + '_domain' => null, + '_default' => 'manea ou li a', + ], $terms); + } + + public function testArgumentNameWithTrait() + { + $terms = $this->p('date-from:2016-05-04'); + + $this->assertEquals([ + '_domain' => null, + 'date-from' => '2016-05-04', + '_default' => '', + ], $terms); + } + + public function testCapitalLetters() + { + $terms = $this->p('Foo:Bar LOL marCi @PERSON'); + + $this->assertEquals([ + '_domain' => 'person', + '_default' => 'lol marci', + 'foo' => 'bar', + ], $terms); + } + + public function testDoubleParenthesis() + { + $terms = $this->p('@papamobile name:(my beautiful name) residual ' + . 'surname:(i love techno)'); + + $this->assertEquals([ + '_domain' => 'papamobile', + 'name' => 'my beautiful name', + '_default' => 'residual', + 'surname' => 'i love techno', + ], $terms); + } + /** * @expectedException \Chill\MainBundle\Search\UnknowSearchNameException */ public function testInvalidSearchName() { - $this->search->getByName("invalid name"); + $this->search->getByName('invalid name'); } - - public function testSimplePattern() - { - $terms = $this->p("@person birthdate:2014-01-02 name:(my name) is not my name"); - - $this->assertEquals(array( - '_domain' => 'person', - 'birthdate' => '2014-01-02', - '_default' => 'is not my name', - 'name' => 'my name' - ), $terms); - } - - public function testWithoutDomain() - { - $terms = $this->p('foo:bar residual'); - - $this->assertEquals(array( - '_domain' => null, - 'foo' => 'bar', - '_default' => 'residual' - ), $terms); - } - - public function testWithoutDefault() - { - $terms = $this->p('@person foo:bar'); - - $this->assertEquals(array( - '_domain' => 'person', - 'foo' => 'bar', - '_default' => '' - ), $terms); - } - - public function testCapitalLetters() - { - $terms = $this->p('Foo:Bar LOL marCi @PERSON'); - - $this->assertEquals(array( - '_domain' => 'person', - '_default' => 'lol marci', - 'foo' => 'bar' - ), $terms); - } - + /** - * @expectedException Chill\MainBundle\Search\ParsingException + * @expectedException \Chill\MainBundle\Search\ParsingException */ public function testMultipleDomainError() { - $term = $this->p("@person @report"); + $term = $this->p('@person @report'); } - - public function testDoubleParenthesis() - { - $terms = $this->p("@papamobile name:(my beautiful name) residual " - . "surname:(i love techno)"); - - $this->assertEquals(array( - '_domain' => 'papamobile', - 'name' => 'my beautiful name', - '_default' => 'residual', - 'surname' => 'i love techno' - ), $terms); - } - - public function testAccentued() - { - //$this->markTestSkipped('accentued characters must be implemented'); - - $terms = $this->p('manço bélier aztèque à saloù ê'); - - $this->assertEquals(array( - '_domain' => NULL, - '_default' => 'manco belier azteque a salou e' - ), $terms); - } - - public function testAccentuedCapitals() - { - //$this->markTestSkipped('accentued characters must be implemented'); - - $terms = $this->p('MANÉÀ oÛ lÎ À'); - - $this->assertEquals(array( - '_domain' => null, - '_default' => 'manea ou li a' - ), $terms); - } - - public function testTrimInParenthesis() - { - $terms = $this->p('foo:(bar )'); - - $this->assertEquals(array( - '_domain' => null, - 'foo' => 'bar', - '_default' => '' - ), $terms); - } - - public function testTrimInDefault() - { - $terms = $this->p(' foo bar '); - - $this->assertEquals(array( - '_domain' => null, - '_default' => 'foo bar' - ), $terms); - } - - public function testArgumentNameWithTrait() - { - $terms = $this->p('date-from:2016-05-04'); - - $this->assertEquals(array( - '_domain' => null, - 'date-from' => '2016-05-04', - '_default' => '' - ), $terms); - } - + /** - * Test the behaviour when no domain is provided in the search pattern : - * the default search should be enabled + * Test the behaviour when no domain is provided in the search pattern : + * the default search should be enabled. */ public function testSearchResultDefault() { $response = $this->search->getSearchResults('default search'); //$this->markTestSkipped(); - - $this->assertEquals(array( - "I am default" - ), $response); + + $this->assertEquals([ + 'I am default', + ], $response); } - + + public function testSearchResultDomainSearch() + { + //add a search service which will be supported + $this->addSearchService( + $this->createNonDefaultDomainSearchService('I am domain foo', 100, true), + 'foo' + ); + + $response = $this->search->getSearchResults('@foo default search'); + + $this->assertEquals([ + 'I am domain foo', + ], $response); + } + /** * @expectedException \Chill\MainBundle\Search\UnknowSearchDomainException */ @@ -200,116 +153,154 @@ class SearchProviderTest extends TestCase $response = $this->search->getSearchResults('@unknow domain'); //$this->markTestSkipped(); - } - - public function testSearchResultDomainSearch() - { - //add a search service which will be supported - $this->addSearchService( - $this->createNonDefaultDomainSearchService("I am domain foo", 100, TRUE), 'foo' - ); - - $response = $this->search->getSearchResults('@foo default search'); - - $this->assertEquals(array( - "I am domain foo" - ), $response); - - } - + public function testSearchWithinSpecificSearchName() { //add a search service which will be supported $this->addSearchService( - $this->createNonDefaultDomainSearchService("I am domain foo", 100, TRUE), 'foo' - ); - + $this->createNonDefaultDomainSearchService('I am domain foo', 100, true), + 'foo' + ); + $response = $this->search->getResultByName('@foo search', 'foo'); - + $this->assertEquals('I am domain foo', $response); - } - + /** * @expectedException \Chill\MainBundle\Search\ParsingException */ public function testSearchWithinSpecificSearchNameInConflictWithSupport() { $response = $this->search->getResultByName('@foo default search', 'bar'); - } - + + public function testSimplePattern() + { + $terms = $this->p('@person birthdate:2014-01-02 name:(my name) is not my name'); + + $this->assertEquals([ + '_domain' => 'person', + 'birthdate' => '2014-01-02', + '_default' => 'is not my name', + 'name' => 'my name', + ], $terms); + } + + public function testTrimInDefault() + { + $terms = $this->p(' foo bar '); + + $this->assertEquals([ + '_domain' => null, + '_default' => 'foo bar', + ], $terms); + } + + public function testTrimInParenthesis() + { + $terms = $this->p('foo:(bar )'); + + $this->assertEquals([ + '_domain' => null, + 'foo' => 'bar', + '_default' => '', + ], $terms); + } + + public function testWithoutDefault() + { + $terms = $this->p('@person foo:bar'); + + $this->assertEquals([ + '_domain' => 'person', + 'foo' => 'bar', + '_default' => '', + ], $terms); + } + + public function testWithoutDomain() + { + $terms = $this->p('foo:bar residual'); + + $this->assertEquals([ + '_domain' => null, + 'foo' => 'bar', + '_default' => 'residual', + ], $terms); + } + /** - * shortcut for executing parse method - * + * Add a search service to the chill.main.search_provider. + * + * Useful for mocking the SearchInterface + * + * @param string $name + */ + private function addSearchService(SearchInterface $search, $name) + { + $this->search + ->addSearchService($search, $name); + } + + private function createDefaultSearchService($result, $order) + { + $mock = $this + ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); + + //set the mock as default + $mock->expects($this->any()) + ->method('isActiveByDefault') + ->will($this->returnValue(true)); + + $mock->expects($this->any()) + ->method('getOrder') + ->will($this->returnValue($order)); + + //set the return value + $mock->expects($this->any()) + ->method('renderResult') + ->will($this->returnValue($result)); + + return $mock; + } + + private function createNonDefaultDomainSearchService($result, $order, $domain) + { + $mock = $this + ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); + + //set the mock as default + $mock->expects($this->any()) + ->method('isActiveByDefault') + ->will($this->returnValue(false)); + + $mock->expects($this->any()) + ->method('getOrder') + ->will($this->returnValue($order)); + + $mock->expects($this->any()) + ->method('supports') + ->will($this->returnValue($domain)); + + //set the return value + $mock->expects($this->any()) + ->method('renderResult') + ->will($this->returnValue($result)); + + return $mock; + } + + /** + * shortcut for executing parse method. + * * @param unknown $pattern + * * @return string[] */ private function p($pattern) { return $this->search->parse($pattern); } - - /** - * Add a search service to the chill.main.search_provider - * - * Useful for mocking the SearchInterface - * - * @param SearchInterface $search - * @param string $name - */ - private function addSearchService(SearchInterface $search, $name) - { - $this->search - ->addSearchService($search, $name); - } - - private function createDefaultSearchService($result, $order) - { - $mock = $this - ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); - - //set the mock as default - $mock->expects($this->any()) - ->method('isActiveByDefault') - ->will($this->returnValue(TRUE)); - - $mock->expects($this->any()) - ->method('getOrder') - ->will($this->returnValue($order)); - - //set the return value - $mock->expects($this->any()) - ->method('renderResult') - ->will($this->returnValue($result)); - - return $mock; - } - - private function createNonDefaultDomainSearchService($result, $order, $domain) - { - $mock = $this - ->getMockForAbstractClass('Chill\MainBundle\Search\AbstractSearch'); - - //set the mock as default - $mock->expects($this->any()) - ->method('isActiveByDefault') - ->will($this->returnValue(FALSE)); - - $mock->expects($this->any()) - ->method('getOrder') - ->will($this->returnValue($order)); - - $mock->expects($this->any()) - ->method('supports') - ->will($this->returnValue($domain)); - - //set the return value - $mock->expects($this->any()) - ->method('renderResult') - ->will($this->returnValue($result)); - - return $mock; - } } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php index fbd3cd4d1..858006cce 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/Authorization/AuthorizationHelperTest.php @@ -1,294 +1,41 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Security\Authorization; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\MainBundle\Test\PrepareUserTrait; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Test\PrepareCenterTrait; use Chill\MainBundle\Test\PrepareScopeTrait; +use Chill\MainBundle\Test\PrepareUserTrait; use Chill\MainBundle\Test\ProphecyTrait; -use Chill\MainBundle\Entity\User; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Security\Core\Role\Role; -use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Entity\Center; +use function array_map; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class AuthorizationHelperTest extends KernelTestCase { - - use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait, ProphecyTrait; - - public function setUp() + use PrepareCenterTrait; + use PrepareScopeTrait; + use PrepareUserTrait; + use ProphecyTrait; + + public function setUp() { static::bootKernel(); } - - /** - * - * @return \Chill\MainBundle\Security\Authorization\AuthorizationHelper - */ - private function getAuthorizationHelper() - { - return static::$container - ->get('chill.main.security.authorization.helper') - ; - } - - /** - * Test function userCanReach of helper. - * - * A user can reach center => the function should return true. - */ - public function testUserCanReachCenter_UserShouldReach() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'ANY_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - - $this->assertTrue($helper->userCanReachCenter($user, $center)); - } - - /** - * Test function userCanReach of helper - * - * A user can not reachcenter =>W the function should return false - */ - public function testUserCanReachCenter_UserShouldNotReach() - { - $centerA = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(2, 'centerB'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'ANY_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - - $this->assertFalse($helper->userCanReachCenter($user, $centerB)); - - } - - public function testUserHasAccess_shouldHaveAccess_EntityWithoutScope() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->getCenter()->willReturn($center); - - $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), - 'CHILL_ROLE')); - } - - public function testUserHasAccess_ShouldHaveAccessWithInheritance_EntityWithoutScope() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_MASTER_ROLE'] - ) - ) - )); - - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->getCenter()->willReturn($center); - - $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), - 'CHILL_INHERITED_ROLE_1')); - } - - - public function testuserHasAccess_UserHasNoRole_EntityWithoutScope() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'ANY_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->getCenter()->willReturn($center); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - /** - * test that a user has no access on a entity, but is granted on the same role - * on another center - */ - public function testUserHasAccess_userHasNoRole_UserHasRoleOnAnotherCenter_EntityWithoutScope() - { - $centerA = $this->prepareCenter(1, 'center'); - $centerB = $this->prepareCenter(2, 'centerB'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'ANY_ROLE'] - ), - array( - 'centerB' => $centerB, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'ANY_ROLE'], - ['scope' => $scope, 'role' => 'CHILL_ROLE'] - ) - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->getCenter()->willReturn($centerA); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testtestUserHasAccess_UserShouldHaveAccess_EntityWithScope() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); - $entity->getCenter()->willReturn($center); - $entity->getScope()->willReturn($scope); - - $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasAccess_UserHasNoRole_EntityWithScope() - { - $center = $this->prepareCenter(1, 'center'); - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); - $entity->getCenter()->willReturn($center); - $entity->getScope()->willReturn($scope); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'ANOTHER_ROLE')); - } - - public function testUserHasAccess_UserHasNoCenter_EntityWithScope() - { - $centerA = $this->prepareCenter(1, 'center'); //the user will have this center - $centerB = $this->prepareCenter(2, 'centerB'); //the entity will have another center - $scope = $this->prepareScope(1, 'default'); - $user = $this->prepareUser(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); - $entity->getCenter()->willReturn($centerB); - $entity->getScope()->willReturn($scope); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - public function testUserHasAccess_UserHasNoScope_EntityWithScope() - { - $center = $this->prepareCenter(1, 'center'); - $scopeA = $this->prepareScope(1, 'default'); //the entity will have this scope - $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope - $user = $this->prepareUser(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scopeB, 'role' => 'CHILL_ROLE'] - ) - ) - )); - $helper = $this->getAuthorizationHelper(); - $entity = $this->getProphet()->prophesize(); - $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); - $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); - $entity->getCenter()->willReturn($center); - $entity->getScope()->willReturn($scopeA); - - $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); - } - - /** - * - * @dataProvider dataProvider_getReachableCenters - * @param Center $shouldHaveCenter - * @param User $user - * @param Role $role - * @param Scope $scope - */ - public function testGetReachableCenters($test, $result, $msg) - { - $this->assertEquals($test, $result, $msg); - } - + public function dataProvider_getReachableCenters() { $this->setUp(); @@ -297,96 +44,95 @@ class AuthorizationHelperTest extends KernelTestCase $scopeA = $this->prepareScope(1, 'scope default'); $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - - $userA = $this->prepareUser(array( - array( - 'center' => $centerA, - 'permissionsGroup' => array( + + $userA = $this->prepareUser([ + [ + 'center' => $centerA, + 'permissionsGroup' => [ ['scope' => $scopeB, 'role' => 'CHILL_ROLE_1'], - ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'] - ) - ), - array( - 'center' => $centerB, - 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], - ['scope' => $scopeC, 'role' => 'CHILL_ROLE_2'] - ) - ) - - )); - + ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], + ], + ], + [ + 'center' => $centerB, + 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], + ['scope' => $scopeC, 'role' => 'CHILL_ROLE_2'], + ], + ], + ]); + $ah = $this->getAuthorizationHelper(); - - return array( - // without scopes - array( - true, - in_array($centerA, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_1'), null)), - 'center A should be available for userA, with role 1 ' - ), - array( - true, - in_array($centerA, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_2'), null)), - 'center A should be available for userA, with role 2 ' - ), - array( - true, - in_array($centerB, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_2'), null)), - 'center A should be available for userA, with role 2 ' - ), - array( - false, - in_array($centerB, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_1'), null)), - 'center B should NOT be available for userA, with role 1 ' - ), - // with scope - array( - true, - in_array($centerA, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_1'), $scopeB)), - 'center A should be available for userA, with role 1, scopeC ' - ), - array( - false, - in_array($centerA, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_2'), $scopeC)), - 'center A should NOT be available for userA, with role 2, scopeA ' - ), - array( - true, - in_array($centerB, $ah->getReachableCenters($userA, - new Role('CHILL_ROLE_2'), $scopeA)), - 'center B should be available for userA, with role 2, scopeA ' - ), - ); - + + return [ + // without scopes + [ + true, + in_array($centerA, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_1'), + null + )), + 'center A should be available for userA, with role 1 ', + ], + [ + true, + in_array($centerA, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_2'), + null + )), + 'center A should be available for userA, with role 2 ', + ], + [ + true, + in_array($centerB, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_2'), + null + )), + 'center A should be available for userA, with role 2 ', + ], + [ + false, + in_array($centerB, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_1'), + null + )), + 'center B should NOT be available for userA, with role 1 ', + ], + // with scope + [ + true, + in_array($centerA, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_1'), + $scopeB + )), + 'center A should be available for userA, with role 1, scopeC ', + ], + [ + false, + in_array($centerA, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_2'), + $scopeC + )), + 'center A should NOT be available for userA, with role 2, scopeA ', + ], + [ + true, + in_array($centerB, $ah->getReachableCenters( + $userA, + new Role('CHILL_ROLE_2'), + $scopeA + )), + 'center B should be available for userA, with role 2, scopeA ', + ], + ]; } - - /** - * - * @dataProvider dataProvider_getReachableScopes - * @param boolean $expectedResult - * @param Scope $testedScope - * @param User $user - * @param Role $role - * @param Center $center - * @param string $message - */ - public function testGetReachableScopes($expectedResult, Scope $testedScope, - User $user, Role $role, Center $center, $message) - { - $reachableScopes = $this->getAuthorizationHelper() - ->getReachableScopes($user, $role, $center); - - $this->assertEquals($expectedResult, in_array($testedScope, $reachableScopes), - $message); - } - + public function dataProvider_getReachableScopes() { $centerA = $this->prepareCenter(1, 'center A'); @@ -394,85 +140,356 @@ class AuthorizationHelperTest extends KernelTestCase $scopeA = $this->prepareScope(1, 'scope default'); $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - - $userA = $this->prepareUser(array( - array( - 'center' => $centerA, - 'permissionsGroup' => array( + + $userA = $this->prepareUser([ + [ + 'center' => $centerA, + 'permissionsGroup' => [ ['scope' => $scopeB, 'role' => 'CHILL_ROLE_1'], - ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'] - ) - ), - array( - 'center' => $centerB, - 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], - ['scope' => $scopeC, 'role' => 'CHILL_ROLE_2'], - ['scope' => $scopeB, 'role' => 'CHILL_ROLE_2'] - ) - ) - - )); - - return array( - array( + ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], + ], + ], + [ + 'center' => $centerB, + 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_ROLE_2'], + ['scope' => $scopeC, 'role' => 'CHILL_ROLE_2'], + ['scope' => $scopeB, 'role' => 'CHILL_ROLE_2'], + ], + ], + ]); + + return [ + [ true, $scopeA, $userA, new Role('CHILL_ROLE_2'), $centerA, - "Assert that a scope is found within accessible scopes" - ), - array( + 'Assert that a scope is found within accessible scopes', + ], + [ false, $scopeB, $userA, new Role('CHILL_ROLE_2'), $centerA, - "Assert that a scope not reachable is NOT found within accessible scopes" - ), - array( + 'Assert that a scope not reachable is NOT found within accessible scopes', + ], + [ false, $scopeB, $userA, new Role('CHILL_ROLE_1'), $centerB, - "Assert that a scope not reachable is not found within accessible scopes." - . " Trying on filter centering" - ) - ); + 'Assert that a scope not reachable is not found within accessible scopes.' + . ' Trying on filter centering', + ], + ]; } - - public function testGetParentRoles() - { - $parentRoles = $this->getAuthorizationHelper() - ->getParentRoles(new Role('CHILL_INHERITED_ROLE_1')); - - $this->assertContains( - 'CHILL_MASTER_ROLE', - \array_map( - function(Role $role) { - return $role->getRole(); - }, - $parentRoles - ), - "Assert that `CHILL_MASTER_ROLE` is a parent of `CHILL_INHERITED_ROLE_1`"); - } - + public function testFindUsersReaching() { $centerA = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository(Center::class) ->findOneByName('Center A'); - + $users = $this->getAuthorizationHelper() - ->findUsersReaching(new Role('CHILL_PERSON_SEE'), - $centerA); - - $usernames = \array_map(function(User $u) { return $u->getUsername(); }, $users); - + ->findUsersReaching( + new Role('CHILL_PERSON_SEE'), + $centerA + ); + + $usernames = array_map(function (User $u) { return $u->getUsername(); }, $users); + $this->assertContains('center a_social', $usernames); } - + + public function testGetParentRoles() + { + $parentRoles = $this->getAuthorizationHelper() + ->getParentRoles(new Role('CHILL_INHERITED_ROLE_1')); + + $this->assertContains( + 'CHILL_MASTER_ROLE', + array_map( + function (Role $role) { + return $role->getRole(); + }, + $parentRoles + ), + 'Assert that `CHILL_MASTER_ROLE` is a parent of `CHILL_INHERITED_ROLE_1`' + ); + } + + /** + * @dataProvider dataProvider_getReachableCenters + * + * @param mixed $test + * @param mixed $result + * @param mixed $msg + */ + public function testGetReachableCenters($test, $result, $msg) + { + $this->assertEquals($test, $result, $msg); + } + + /** + * @dataProvider dataProvider_getReachableScopes + * + * @param bool $expectedResult + * @param string $message + */ + public function testGetReachableScopes( + $expectedResult, + Scope $testedScope, + User $user, + Role $role, + Center $center, + $message + ) { + $reachableScopes = $this->getAuthorizationHelper() + ->getReachableScopes($user, $role, $center); + + $this->assertEquals( + $expectedResult, + in_array($testedScope, $reachableScopes), + $message + ); + } + + public function testtestUserHasAccessUserShouldHaveAccessEntityWithScope() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); + $entity->getCenter()->willReturn($center); + $entity->getScope()->willReturn($scope); + + $this->assertTrue($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + /** + * Test function userCanReach of helper. + * + * A user can not reachcenter =>W the function should return false + */ + public function testUserCanReachCenterUserShouldNotReach() + { + $centerA = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(2, 'centerB'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'ANY_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + + $this->assertFalse($helper->userCanReachCenter($user, $centerB)); + } + + /** + * Test function userCanReach of helper. + * + * A user can reach center => the function should return true. + */ + public function testUserCanReachCenterUserShouldReach() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'ANY_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + + $this->assertTrue($helper->userCanReachCenter($user, $center)); + } + + public function testUserHasAccessShouldHaveAccessEntityWithoutScope() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->getCenter()->willReturn($center); + + $this->assertTrue($helper->userHasAccess( + $user, + $entity->reveal(), + 'CHILL_ROLE' + )); + } + + public function testUserHasAccessShouldHaveAccessWithInheritanceEntityWithoutScope() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_MASTER_ROLE'], + ], + ], + ]); + + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->getCenter()->willReturn($center); + + $this->assertTrue($helper->userHasAccess( + $user, + $entity->reveal(), + 'CHILL_INHERITED_ROLE_1' + )); + } + + public function testUserHasAccessUserHasNoCenterEntityWithScope() + { + $centerA = $this->prepareCenter(1, 'center'); //the user will have this center + $centerB = $this->prepareCenter(2, 'centerB'); //the entity will have another center + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); + $entity->getCenter()->willReturn($centerB); + $entity->getScope()->willReturn($scope); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testuserHasAccessUserHasNoRoleEntityWithoutScope() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'ANY_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->getCenter()->willReturn($center); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testUserHasAccessUserHasNoRoleEntityWithScope() + { + $center = $this->prepareCenter(1, 'center'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); + $entity->getCenter()->willReturn($center); + $entity->getScope()->willReturn($scope); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'ANOTHER_ROLE')); + } + + /** + * test that a user has no access on a entity, but is granted on the same role + * on another center. + */ + public function testUserHasAccessUserHasNoRoleUserHasRoleOnAnotherCenterEntityWithoutScope() + { + $centerA = $this->prepareCenter(1, 'center'); + $centerB = $this->prepareCenter(2, 'centerB'); + $scope = $this->prepareScope(1, 'default'); + $user = $this->prepareUser([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'ANY_ROLE'], + ], + [ + 'centerB' => $centerB, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'ANY_ROLE'], + ['scope' => $scope, 'role' => 'CHILL_ROLE'], + ], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->getCenter()->willReturn($centerA); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + public function testUserHasAccessUserHasNoScopeEntityWithScope() + { + $center = $this->prepareCenter(1, 'center'); + $scopeA = $this->prepareScope(1, 'default'); //the entity will have this scope + $scopeB = $this->prepareScope(2, 'other'); //the user will be granted this scope + $user = $this->prepareUser([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scopeB, 'role' => 'CHILL_ROLE'], + ], + ], + ]); + $helper = $this->getAuthorizationHelper(); + $entity = $this->getProphet()->prophesize(); + $entity->willImplement('\Chill\MainBundle\Entity\HasCenterInterface'); + $entity->willImplement('\Chill\MainBundle\Entity\HasScopeInterface'); + $entity->getCenter()->willReturn($center); + $entity->getScope()->willReturn($scopeA); + + $this->assertFalse($helper->userHasAccess($user, $entity->reveal(), 'CHILL_ROLE')); + } + + /** + * @return \Chill\MainBundle\Security\Authorization\AuthorizationHelper + */ + private function getAuthorizationHelper() + { + return static::$container + ->get('chill.main.security.authorization.helper'); + } } diff --git a/src/Bundle/ChillMainBundle/Tests/Security/PasswordRecover/TokenManagerTest.php b/src/Bundle/ChillMainBundle/Tests/Security/PasswordRecover/TokenManagerTest.php index abb36459b..7c6ecd565 100644 --- a/src/Bundle/ChillMainBundle/Tests/Security/PasswordRecover/TokenManagerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Security/PasswordRecover/TokenManagerTest.php @@ -1,58 +1,50 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Tests\PasswordRecover; - -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\MainBundle\Security\PasswordRecover\TokenManager; -use Chill\MainBundle\Entity\User; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Tests\PasswordRecover; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\PasswordRecover\TokenManager; +use DateInterval; +use DateTimeImmutable; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; + +/** + * @internal + * @coversNothing */ class TokenManagerTest extends KernelTestCase { protected $tokenManager; - - public static function setUpBefore() - { - - } - + public function setUp() { self::bootKernel(); - + $logger = self::$container ->get('logger'); - + $this->tokenManager = new TokenManager('secret', $logger); } - public function testGenerate() + public static function setUpBefore() + { + } + + public function testGenerate() { $tokenManager = $this->tokenManager; $user = (new User())->setUsernameCanonical('test'); - $expiration = new \DateTimeImmutable('tomorrow'); - + $expiration = new DateTimeImmutable('tomorrow'); + $tokens = $tokenManager->generate($user, $expiration); - + $this->assertInternalType('array', $tokens); $this->assertArrayHasKey('h', $tokens); $this->assertArrayHasKey('t', $tokens); @@ -60,57 +52,57 @@ class TokenManagerTest extends KernelTestCase $this->assertNotEmpty($tokens['t']); $this->assertEquals($user->getUsernameCanonical(), $tokens['u']); } - + /** * @expectedException \UnexpectedValueException */ - public function testGenerateEmptyUsernameCanonical() + public function testGenerateEmptyUsernameCanonical() { $tokenManager = $this->tokenManager; // set a username, but not a username canonical $user = (new User())->setUsername('test'); - $expiration = new \DateTimeImmutable('tomorrow'); - + $expiration = new DateTimeImmutable('tomorrow'); + $tokenManager->generate($user, $expiration); } - + public function testVerify() { $tokenManager = $this->tokenManager; $user = (new User())->setUsernameCanonical('test'); - $expiration = new \DateTimeImmutable('tomorrow'); - + $expiration = new DateTimeImmutable('tomorrow'); + $tokens = $tokenManager->generate($user, $expiration); - + $hash = $tokens[TokenManager::HASH]; $token = $tokens[TokenManager::TOKEN]; $timestamp = $tokens[TokenManager::TIMESTAMP]; - + $verification = $tokenManager->verify($hash, $token, $user, $timestamp); - + $this->assertTrue($verification); - + // test with altering token - $this->assertFalse($tokenManager->verify($hash.'5', $token, $user, $timestamp)); - $this->assertFalse($tokenManager->verify($hash, $token.'25', $user, $timestamp)); + $this->assertFalse($tokenManager->verify($hash . '5', $token, $user, $timestamp)); + $this->assertFalse($tokenManager->verify($hash, $token . '25', $user, $timestamp)); $this->assertFalse($tokenManager->verify($hash, $token, $user->setUsernameCanonical('test2'), $timestamp)); - $this->assertFalse($tokenManager->verify($hash, $token, $user, $timestamp+1)); + $this->assertFalse($tokenManager->verify($hash, $token, $user, $timestamp + 1)); } - + public function testVerifyExpiredFails() { $tokenManager = $this->tokenManager; $user = (new User())->setUsernameCanonical('test'); - $expiration = (new \DateTimeImmutable('now'))->sub(new \DateInterval('PT1S')); - + $expiration = (new DateTimeImmutable('now'))->sub(new DateInterval('PT1S')); + $tokens = $tokenManager->generate($user, $expiration); - + $hash = $tokens[TokenManager::HASH]; $token = $tokens[TokenManager::TOKEN]; $timestamp = $tokens[TokenManager::TIMESTAMP]; - + $verification = $tokenManager->verify($hash, $token, $user, $timestamp); - + $this->assertFalse($verification); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Services/ChillMenuTwigFunctionTest.php b/src/Bundle/ChillMainBundle/Tests/Services/ChillMenuTwigFunctionTest.php index a85ff9710..b46cc37a7 100644 --- a/src/Bundle/ChillMainBundle/Tests/Services/ChillMenuTwigFunctionTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Services/ChillMenuTwigFunctionTest.php @@ -1,54 +1,44 @@ - * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests\Services; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\DomCrawler\Crawler; /** - * Test the Twig function 'chill_menu' + * Test the Twig function 'chill_menu'. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ChillMenuTwigFunctionTest extends KernelTestCase { - private static $templating; - + public static function setUpBeforeClass() { - self::bootKernel(array('environment' => 'test')); + self::bootKernel(['environment' => 'test']); static::$templating = static::$container ->get('templating'); $pathToBundle = static::$container->getParameter('kernel.bundles_metadata')['ChillMainBundle']['path']; //load templates in Tests/Resources/views static::$container->get('twig.loader') - ->addPath($pathToBundle.'/Resources/test/views/', $namespace = 'tests'); + ->addPath($pathToBundle . '/Resources/test/views/', $namespace = 'tests'); } - + public function testNormalMenu() { $content = static::$templating->render('@tests/menus/normalMenu.html.twig'); - $this->assertContains('ul', $content, - "test that the file contains an ul tag" + $this->assertContains( + 'ul', + $content, + 'test that the file contains an ul tag' ); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Services/MenuComposerTest.php b/src/Bundle/ChillMainBundle/Tests/Services/MenuComposerTest.php index 98bf23386..d639224c6 100644 --- a/src/Bundle/ChillMainBundle/Tests/Services/MenuComposerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Services/MenuComposerTest.php @@ -1,46 +1,51 @@ + * @internal + * @coversNothing */ class MenuComposerTest extends KernelTestCase { - /** - * * @var \Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader; */ private $loader; - + /** - * * @var \Chill\MainBundle\DependencyInjection\Services\MenuComposer; */ private $menuComposer; - + public function setUp() { - self::bootKernel(array('environment' => 'test')); + self::bootKernel(['environment' => 'test']); $this->menuComposer = static::$container - ->get('chill.main.menu_composer'); + ->get('chill.main.menu_composer'); } - + /** * @covers \Chill\MainBundle\Routing\MenuComposer */ public function testMenuComposer() { $collection = new RouteCollection(); - + $routes = $this->menuComposer->getRoutesFor('dummy0'); - + $this->assertInternalType('array', $routes); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php b/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php index d95969b9d..2ba1d03ec 100644 --- a/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Templating/ChillMarkdownRenderExtensionTest.php @@ -1,76 +1,69 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Tests\Templating; - -use PHPUnit\Framework\TestCase; -use Chill\MainBundle\Templating\ChillMarkdownRenderExtension; /** - * Test the service ChillMarkdownRenderExtension - * + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\MainBundle\Tests\Templating; + +use Chill\MainBundle\Templating\ChillMarkdownRenderExtension; +use PHPUnit\Framework\TestCase; + +/** + * Test the service ChillMarkdownRenderExtension. + * * @internal we do not want to test the markdown transformation. We just want to - * test that the markdown is correctly transformed into html, and that the html + * test that the markdown is correctly transformed into html, and that the html * is safe. + * @coversNothing */ class ChillMarkdownRenderExtensionTest extends TestCase { - - private const SIMPLE_MARKDOWN = <<test +

Text.

+ HTML; + + private const SIMPLE_MARKDOWN = <<<'MD' + # test + + Text. + MD; + + private const UNAUTHORIZED_HTML = <<<'HTML' +

<script>alert("ok");</script>

+ HTML; + + private const UNAUTHORIZED_MARKDOWN = <<<'MD' + + MD; -Text. -MD; - - private const SIMPLE_HTML = <<test -

Text.

-HTML; - - private const UNAUTHORIZED_MARKDOWN = <<alert("ok"); -MD; - - private const UNAUTHORIZED_HTML = <<<script>alert("ok");</script>

-HTML; - /** - * Test that the markdown input is transformed into html + * Test that the markdown input is transformed into html. */ public function testRendering() { $extension = new ChillMarkdownRenderExtension(); - - $this->assertEquals(self::SIMPLE_HTML, - $extension->renderMarkdownToHtml(self::SIMPLE_MARKDOWN)); + + $this->assertEquals( + self::SIMPLE_HTML, + $extension->renderMarkdownToHtml(self::SIMPLE_MARKDOWN) + ); } - + /** - * Test that the output of the markdown content is sanitized + * Test that the output of the markdown content is sanitized. */ public function testSecurity() { $extension = new ChillMarkdownRenderExtension(); - - $this->assertEquals(self::UNAUTHORIZED_HTML, - $extension->renderMarkdownToHtml(self::UNAUTHORIZED_MARKDOWN)); + + $this->assertEquals( + self::UNAUTHORIZED_HTML, + $extension->renderMarkdownToHtml(self::UNAUTHORIZED_MARKDOWN) + ); } } diff --git a/src/Bundle/ChillMainBundle/Tests/TestHelper.php b/src/Bundle/ChillMainBundle/Tests/TestHelper.php index a969eeeb3..4c009ae83 100644 --- a/src/Bundle/ChillMainBundle/Tests/TestHelper.php +++ b/src/Bundle/ChillMainBundle/Tests/TestHelper.php @@ -1,21 +1,10 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Tests; @@ -23,25 +12,25 @@ namespace Chill\MainBundle\Tests; use Symfony\Component\BrowserKit\Client; /** - * Provide useful methods for tests - * - * @author Julien Fastré - * @author Champs Libres + * Provide useful methods for tests. */ class TestHelper { /** - * create a client authenticated with an user - * - * @param WebTestCase $testCase + * create a client authenticated with an user. + * + * @param mixed $username + * @param mixed $password + * * @return \Symfony\Component\BrowserKit\Client authenticated client */ - public static function getAuthenticatedClientOptions($username = 'center a_social', - $password = 'password') - { - return array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => $password, - ); + public static function getAuthenticatedClientOptions( + $username = 'center a_social', + $password = 'password' + ) { + return [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => $password, + ]; } } diff --git a/src/Bundle/ChillMainBundle/Tests/Util/CountriesInfoTest.php b/src/Bundle/ChillMainBundle/Tests/Util/CountriesInfoTest.php index 955ec4382..7a2209114 100644 --- a/src/Bundle/ChillMainBundle/Tests/Util/CountriesInfoTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Util/CountriesInfoTest.php @@ -1,48 +1,58 @@ assertStringStartsWith("AS AF AFG 004 Afghanistan, Islamic Republic of", - $raw); + $continents = CountriesInfo::getContinentsCodes(); + + $this->assertContains('EU', $continents); } - - public function testGetArrayCountriesData() + + public function testGetArrayCountriesData() { $data = CountriesInfo::getArrayCountriesData(); - + $this->assertNotNull($data); - $this->assertContains(array( - "AS", "AF", "AFG", "004", "Afghanistan, Islamic Republic of" - ), $data); + $this->assertContains([ + 'AS', 'AF', 'AFG', '004', 'Afghanistan, Islamic Republic of', + ], $data); } - + public function testGetCountryCodeByContinents() { $countries = CountriesInfo::getCountriesCodeByContinent('EU'); - + $this->assertContains('BE', $countries); $this->assertContains('FR', $countries); $this->assertContains('GB', $countries); } - - public function getGetContinentsCodes() + + public function testGetCountryData() { - $continents = CountriesInfo::getContinentsCodes(); - - $this->assertContains('EU', $continents); + $raw = CountriesInfo::getCountriesData(); + + $this->assertStringStartsWith( + 'AS AF AFG 004 Afghanistan, Islamic Republic of', + $raw + ); } } diff --git a/src/Bundle/ChillMainBundle/Tests/bootstrap.php b/src/Bundle/ChillMainBundle/Tests/bootstrap.php index 9211155e5..0eb126c4f 100644 --- a/src/Bundle/ChillMainBundle/Tests/bootstrap.php +++ b/src/Bundle/ChillMainBundle/Tests/bootstrap.php @@ -1,8 +1,14 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Timeline; -use Doctrine\ORM\Query\ResultSetMapping; +use DateTime; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query\ResultSetMapping; +use LogicException; use Symfony\Component\DependencyInjection\ContainerAwareInterface; /** - * Build timeline - * - * @author Julien Fastré + * Build timeline. */ class TimelineBuilder implements ContainerAwareInterface { - use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - + /** - * * @var \Doctrine\ORM\EntityManagerInterface */ private $em; - + /** - * Record provider - * + * Record provider. + * * This array has the structure `[ 'service id' => $service ]` * * @var TimelineProviderInterface[] */ private $providers = []; - + /** - * Record provider and their context - * + * Record provider and their context. + * * This array has the structure `[ 'context' => [ 'service id' ] ]` * * @var array */ private $providersByContext = []; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - + /** - * return an HTML string with timeline - * - * This function must be called from controller - * - * @example https://redmine.champs-libres.coop/projects/chillperson/repository/revisions/bd2e1b1808f73e39532e9538413025df5487cad0/entry/Controller/TimelinePersonController.php#L47 the implementation in person bundle - * - * @param string $context - * @param array $args arguments defined by the bundle which create the context - * @param int $firstItem first item number - * @param int $number number of items by page - * @return string an HTML representation, must be included using `|raw` filter - */ - public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20) - { - $union = $this->buildUnionQuery($context, $args); - - //add ORDER BY clause and LIMIT - $query = $union . sprintf(' ORDER BY date DESC LIMIT %d OFFSET %d', - $number, $firstItem); - - // run query and handle results - $fetched = $this->runUnionQuery($query); - $entitiesByKey = $this->getEntities($fetched, $context); - - return $this->render($fetched, $entitiesByKey, $context, $args); - } - - /** - * Return the number of items for the given context and args - * - * @param unknown $context - * @param array $args - * @return mixed|\Doctrine\DBAL\Driver\Statement|NULL - */ - public function countItems($context, array $args) - { - $union = $this->buildUnionQuery($context, $args); - - // embed the union query inside a count query - $count = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $union); - - $rsm = (new ResultSetMapping()) - ->addScalarResult('total', 'total', Type::INTEGER); - - return $this->em->createNativeQuery($count, $rsm) - ->getSingleScalarResult(); - } - - /** - * add a provider id + * add a provider id. * * @internal This function is called by the TimelineCompilerClass * @@ -125,161 +64,170 @@ class TimelineBuilder implements ContainerAwareInterface $this->providersByContext[$context][] = $id; $this->providers[$id] = $provider; } - + /** - * Get providers by context + * Return the number of items for the given context and args. + * + * @param unknown $context + * + * @return \Doctrine\DBAL\Driver\Statement|mixed|null + */ + public function countItems($context, array $args) + { + $union = $this->buildUnionQuery($context, $args); + + // embed the union query inside a count query + $count = sprintf('SELECT COUNT(sq.id) AS total FROM (%s) as sq', $union); + + $rsm = (new ResultSetMapping()) + ->addScalarResult('total', 'total', Type::INTEGER); + + return $this->em->createNativeQuery($count, $rsm) + ->getSingleScalarResult(); + } + + /** + * Get providers by context. * * @param string $context + * * @return TimelineProviderInterface[] */ public function getProvidersByContext($context) { //throw an exception if no provider have been defined for this context if (!array_key_exists($context, $this->providersByContext)) { - throw new \LogicException(sprintf('No builders have been defined for "%s"' + throw new LogicException(sprintf('No builders have been defined for "%s"' . ' context', $context)); } - + $providers = []; - - foreach($this->providersByContext[$context] as $providerId) { + + foreach ($this->providersByContext[$context] as $providerId) { $providers[] = $this->providers[$providerId]; } - + return $providers; } - + /** - * build the UNION query with all providers + * return an HTML string with timeline. * - * @uses self::buildSelectQuery to build individual SELECT queries + * This function must be called from controller + * + * @example https://redmine.champs-libres.coop/projects/chillperson/repository/revisions/bd2e1b1808f73e39532e9538413025df5487cad0/entry/Controller/TimelinePersonController.php#L47 the implementation in person bundle * * @param string $context - * @param mixed $args - * @param int $page - * @param int $number - * @return string - * @throws \LogicException if no builder have been defined for this context + * @param array $args arguments defined by the bundle which create the context + * @param int $firstItem first item number + * @param int $number number of items by page + * + * @return string an HTML representation, must be included using `|raw` filter */ - private function buildUnionQuery($context, array $args) + public function getTimelineHTML($context, array $args, $firstItem = 0, $number = 20) { - //append SELECT queries with UNION keyword between them - $union = ''; - foreach($this->getProvidersByContext($context) as $provider) { - $select = $this->buildSelectQuery($provider, $context, $args); - $append = ($union === '') ? $select : ' UNION '.$select; - $union .= $append; - } - - return $union; + $union = $this->buildUnionQuery($context, $args); + + //add ORDER BY clause and LIMIT + $query = $union . sprintf( + ' ORDER BY date DESC LIMIT %d OFFSET %d', + $number, + $firstItem + ); + + // run query and handle results + $fetched = $this->runUnionQuery($query); + $entitiesByKey = $this->getEntities($fetched, $context); + + return $this->render($fetched, $entitiesByKey, $context, $args); } - + /** - * return the SQL SELECT query as a string, + * return the SQL SELECT query as a string,. * * @uses TimelineProfiderInterface::fetchQuery use the fetchQuery function + * * @param \Chill\MainBundle\Timeline\TimelineProviderInterface $provider * @param string $context * @param mixed[] $args + * * @return string */ private function buildSelectQuery(TimelineProviderInterface $provider, $context, array $args) { $data = $provider->fetchQuery($context, $args); - + return sprintf( - 'SELECT %s AS id, ' + 'SELECT %s AS id, ' . '%s AS "date", ' . "'%s' AS type " . 'FROM %s ' . 'WHERE %s', - $data['id'], - $data['date'], - $data['type'], - $data['FROM'], - $data['WHERE']); + $data['id'], + $data['date'], + $data['type'], + $data['FROM'], + $data['WHERE'] + ); } - + /** - * run the UNION query and return result as an array + * build the UNION query with all providers. * - * @param string $query - * @return array - */ - private function runUnionQuery($query) - { - $resultSetMapping = (new ResultSetMapping()) - ->addScalarResult('id', 'id') - ->addScalarResult('type', 'type') - ->addScalarResult('date', 'date'); - - return $this->em->createNativeQuery($query, $resultSetMapping) - ->getArrayResult(); - } - - /** + * @uses self::buildSelectQuery to build individual SELECT queries * - * @param array $queriedIds * @param string $context + * @param mixed $args + * + * @throws LogicException if no builder have been defined for this context + * + * @return string + */ + private function buildUnionQuery($context, array $args) + { + //append SELECT queries with UNION keyword between them + $union = ''; + + foreach ($this->getProvidersByContext($context) as $provider) { + $select = $this->buildSelectQuery($provider, $context, $args); + $append = ('' === $union) ? $select : ' UNION ' . $select; + $union .= $append; + } + + return $union; + } + + /** + * @param string $context + * * @return array with the form array($type => [$entity, $entity, $entity]) */ private function getEntities(array $queriedIds, $context) { //gather entities by type to pass all id with same type to the TimelineProvider. - $idsByType = array(); - - foreach($queriedIds as $result) { + $idsByType = []; + + foreach ($queriedIds as $result) { $idsByType[$result['type']][] = $result['id']; } - + //fetch entities from providers - $entitiesByType = array(); + $entitiesByType = []; + foreach ($idsByType as $type => $ids) { //iterate providers for current context - foreach($this->getProvidersByContext($context) as $provider) { + foreach ($this->getProvidersByContext($context) as $provider) { if ($provider->supportsType($type)) { $entitiesByType[$type] = $provider->getEntities($ids); + break; //we assume that providers have unique keys => we break the loop } } } - + return $entitiesByType; } - - /** - * render the timeline as HTML - * - * @param array $fetched - * @param array $entitiesByType - * @param string $context - * @param mixed[] $args - * @return string the HTML representation of the timeline - */ - private function render(array $fetched, array $entitiesByType, $context, array $args) - { - //add results to a pretty array - $timelineEntries = array(); - foreach ($fetched as $result) { - $data = $this->getTemplateData( - $result['type'], - $entitiesByType[$result['type']][$result['id']], //the entity - $context, - $args); - $timelineEntry['date'] = new \DateTime($result['date']); - $timelineEntry['template'] = $data['template']; - $timelineEntry['template_data'] = $data['template_data']; - - $timelineEntries[] = $timelineEntry; - } - - return $this->container->get('templating') - ->render('@ChillMain/Timeline/index.html.twig', array( - 'results' => $timelineEntries - )); - - } - + /** * get the template data from the provider for the given entity, by type. * @@ -287,14 +235,66 @@ class TimelineBuilder implements ContainerAwareInterface * @param mixed $entity * @param string $context * @param mixed[] $args + * * @return array the template data fetched from the provider */ private function getTemplateData($type, $entity, $context, array $args) { - foreach($this->getProvidersByContext($context) as $provider) { + foreach ($this->getProvidersByContext($context) as $provider) { if ($provider->supportsType($type)) { return $provider->getEntityTemplate($entity, $context, $args); } } } + + /** + * render the timeline as HTML. + * + * @param string $context + * @param mixed[] $args + * + * @return string the HTML representation of the timeline + */ + private function render(array $fetched, array $entitiesByType, $context, array $args) + { + //add results to a pretty array + $timelineEntries = []; + + foreach ($fetched as $result) { + $data = $this->getTemplateData( + $result['type'], + $entitiesByType[$result['type']][$result['id']], //the entity + $context, + $args + ); + $timelineEntry['date'] = new DateTime($result['date']); + $timelineEntry['template'] = $data['template']; + $timelineEntry['template_data'] = $data['template_data']; + + $timelineEntries[] = $timelineEntry; + } + + return $this->container->get('templating') + ->render('@ChillMain/Timeline/index.html.twig', [ + 'results' => $timelineEntries, + ]); + } + + /** + * run the UNION query and return result as an array. + * + * @param string $query + * + * @return array + */ + private function runUnionQuery($query) + { + $resultSetMapping = (new ResultSetMapping()) + ->addScalarResult('id', 'id') + ->addScalarResult('type', 'type') + ->addScalarResult('date', 'date'); + + return $this->em->createNativeQuery($query, $resultSetMapping) + ->getArrayResult(); + } } diff --git a/src/Bundle/ChillMainBundle/Timeline/TimelineProviderInterface.php b/src/Bundle/ChillMainBundle/Timeline/TimelineProviderInterface.php index abe695e75..dda0a2a32 100644 --- a/src/Bundle/ChillMainBundle/Timeline/TimelineProviderInterface.php +++ b/src/Bundle/ChillMainBundle/Timeline/TimelineProviderInterface.php @@ -1,29 +1,21 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Timeline; +use LogicException; + /** - * Interface for service providing info to timeline - * + * Interface for service providing info to timeline. + * * Services implementing those interface must be tagged like this : - * + * * ``` * services: * my_timeline: @@ -34,97 +26,96 @@ namespace Chill\MainBundle\Timeline; * # a second 'center' context : * - { name: timeline, context: center } * ``` - * + * * The bundle which will call the timeline will document available context and * the arguments provided by the context. - * - * - * @author Julien Fastré */ interface TimelineProviderInterface { - /** - * provide data to build a SQL SELECT query to fetch entities - * + * provide data to build a SQL SELECT query to fetch entities. + * * The TimeLineBuilder will create a full SELECT query and append * the query into an UNION of SELECT queries. This permit to fetch * all entities from different table in a single query. - * + * * The associative array MUST have the following key : * - `id` : the name of the id column * - `type`: a string to indicate the type * - `date`: the name of the datetime column, used to order entities by date * - `FROM` (in capital) : the FROM clause. May contains JOIN instructions - * + * * Those key are optional: - * - `WHERE` (in capital) : the WHERE clause. - * + * - `WHERE` (in capital) : the WHERE clause. + * * Where relevant, the data must be quoted to avoid SQL injection. - * + * * `$context` and `$args` are defined by the bundle which will call the timeline - * rendering. - * + * rendering. + * * @param string $context * @param mixed[] $args the argument to the context. + * * @return string[] * @throw \LogicException if the context is not supported */ public function fetchQuery($context, array $args); - - /** - * Indicate if the result type may be handled by the service - * - * @param string $type the key present in the SELECT query - * @return boolean - */ - public function supportsType($type); /** * fetch entities from db into an associative array. The keys **MUST BE** - * the id - * - * All ids returned by all SELECT queries + * the id. + * + * All ids returned by all SELECT queries * (@see TimeLineProviderInterface::fetchQuery) and with the type * supported by the provider (@see TimelineProviderInterface::supportsType) * will be passed as argument. - * + * * @param array $ids an array of id + * * @return mixed[] an associative array of entities, with id as key */ public function getEntities(array $ids); - + /** * return an associative array with argument to render the entity - * in an html template, which will be included in the timeline page - * + * in an html template, which will be included in the timeline page. + * * The result must have the following key : - * + * * - `template` : the template FQDN * - `template_data`: the data required by the template - * - * + * + * * Example: - * + * * ``` - * array( + * array( * 'template' => 'ChillMyBundle:timeline:template.html.twig', * 'template_data' => array( - * 'accompanyingPeriod' => $entity, - * 'person' => $args['person'] + * 'accompanyingPeriod' => $entity, + * 'person' => $args['person'] * ) * ); * ``` - * + * * `$context` and `$args` are defined by the bundle which will call the timeline - * rendering. - * + * rendering. + * * @param type $entity * @param type $context - * @param array $args + * + * @throws LogicException if the context is not supported + * * @return mixed[] - * @throws \LogicException if the context is not supported */ public function getEntityTemplate($entity, $context, array $args); - + + /** + * Indicate if the result type may be handled by the service. + * + * @param string $type the key present in the SELECT query + * + * @return bool + */ + public function supportsType($type); } diff --git a/src/Bundle/ChillMainBundle/Util/CountriesInfo.php b/src/Bundle/ChillMainBundle/Util/CountriesInfo.php index a6dfbee49..5577e4543 100644 --- a/src/Bundle/ChillMainBundle/Util/CountriesInfo.php +++ b/src/Bundle/ChillMainBundle/Util/CountriesInfo.php @@ -1,361 +1,367 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Validation\Constraint; use Symfony\Component\Validator\Constraint; /** - * * @Annotation */ class PhonenumberConstraint extends Constraint { - public $notMobileMessage = "This is not a mobile phonenumber"; - - public $notLandlineMessage = "This is not a landline phonenumber"; - - public $notValidMessage = "This is not a valid phonenumber"; - + public $notLandlineMessage = 'This is not a landline phonenumber'; + + public $notMobileMessage = 'This is not a mobile phonenumber'; + + public $notValidMessage = 'This is not a valid phonenumber'; + /** - * The type of phone: landline (not able to receive sms) or mobile (can receive sms) + * The type of phone: landline (not able to receive sms) or mobile (can receive sms). * * @var string 'landline', 'mobile' or 'any' */ - public $type = null; - + public $type; + public function validatedBy() { return \Chill\MainBundle\Validation\Validator\ValidPhonenumber::class; diff --git a/src/Bundle/ChillMainBundle/Validation/Constraint/RoleScopeScopePresenceConstraint.php b/src/Bundle/ChillMainBundle/Validation/Constraint/RoleScopeScopePresenceConstraint.php index 9f9b6381b..4e576db74 100644 --- a/src/Bundle/ChillMainBundle/Validation/Constraint/RoleScopeScopePresenceConstraint.php +++ b/src/Bundle/ChillMainBundle/Validation/Constraint/RoleScopeScopePresenceConstraint.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Validation\Constraint; @@ -22,25 +12,22 @@ namespace Chill\MainBundle\Validation\Constraint; use Symfony\Component\Validator\Constraint; /** - * Check that a role scope has a scope if required - * - * @author Julien Fastré + * Check that a role scope has a scope if required. */ class RoleScopeScopePresenceConstraint extends Constraint { - - public $messagePresenceRequired = "The role \"%role%\" require to be associated with " - . "a scope."; - public $messageNullRequired = "The role \"%role%\" should not be associated with a scope."; - - public function validatedBy() - { - return 'role_scope_scope_presence'; - } - + public $messageNullRequired = 'The role "%role%" should not be associated with a scope.'; + + public $messagePresenceRequired = 'The role "%role%" require to be associated with ' + . 'a scope.'; + public function getTargets() { return self::CLASS_CONSTRAINT; } - + + public function validatedBy() + { + return 'role_scope_scope_presence'; + } } diff --git a/src/Bundle/ChillMainBundle/Validation/Constraint/UserUniqueEmailAndUsernameConstraint.php b/src/Bundle/ChillMainBundle/Validation/Constraint/UserUniqueEmailAndUsernameConstraint.php index 1cd481dd7..3944d3ac2 100644 --- a/src/Bundle/ChillMainBundle/Validation/Constraint/UserUniqueEmailAndUsernameConstraint.php +++ b/src/Bundle/ChillMainBundle/Validation/Constraint/UserUniqueEmailAndUsernameConstraint.php @@ -1,42 +1,30 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Validation\Constraint; - -use Symfony\Component\Validator\Constraint; -use Chill\MainBundle\Validation\Validator\UserUniqueEmailAndUsername; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Validation\Constraint; + +use Chill\MainBundle\Validation\Validator\UserUniqueEmailAndUsername; +use Symfony\Component\Validator\Constraint; + class UserUniqueEmailAndUsernameConstraint extends Constraint { - public $messageDuplicateUsername = "A user with the same or a close username already exists"; - public $messageDuplicateEmail = "A user with the same or a close email already exists"; - + public $messageDuplicateEmail = 'A user with the same or a close email already exists'; + + public $messageDuplicateUsername = 'A user with the same or a close username already exists'; + + public function getTargets() + { + return [self::CLASS_CONSTRAINT]; + } + public function validatedBy() { return UserUniqueEmailAndUsername::class; } - - public function getTargets() - { - return [ self::CLASS_CONSTRAINT ]; - } } diff --git a/src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php b/src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php index e6681738a..46741f9eb 100644 --- a/src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php +++ b/src/Bundle/ChillMainBundle/Validation/Validator/RoleScopeScopePresence.php @@ -1,60 +1,45 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\MainBundle\Validation\Validator; -use Chill\MainBundle\Security\RoleProvider; use Chill\MainBundle\Entity\RoleScope; -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; +use Chill\MainBundle\Security\RoleProvider; use Chill\MainBundle\Validation\Constraint\RoleScopeScopePresenceConstraint; use Psr\Log\LoggerInterface; +use RuntimeException; use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; -/** - * - * - * @author Julien Fastré - */ class RoleScopeScopePresence extends ConstraintValidator { /** - * - * @var RoleProvider - */ - private $roleProvider; - - /** - * * @var LoggerInterface */ private $logger; - + + /** + * @var RoleProvider + */ + private $roleProvider; + /** - * * @var TranslatorInterface */ private $translator; - - public function __construct(RoleProvider $roleProvider, LoggerInterface $logger, - TranslatorInterface $translator) - { + + public function __construct( + RoleProvider $roleProvider, + LoggerInterface $logger, + TranslatorInterface $translator + ) { $this->roleProvider = $roleProvider; $this->logger = $logger; $this->translator = $translator; @@ -62,41 +47,37 @@ class RoleScopeScopePresence extends ConstraintValidator public function validate($value, Constraint $constraint) { - if (! $value instanceof RoleScope) { - throw new \RuntimeException('The validated object is not an instance of roleScope'); + if (!$value instanceof RoleScope) { + throw new RuntimeException('The validated object is not an instance of roleScope'); } - - if (! $constraint instanceof RoleScopeScopePresenceConstraint) { - throw new \RuntimeException('This validator should be used with RoleScopScopePresenceConstraint'); + + if (!$constraint instanceof RoleScopeScopePresenceConstraint) { + throw new RuntimeException('This validator should be used with RoleScopScopePresenceConstraint'); } - + $this->logger->debug('begin validation of a role scope instance'); - + //if the role scope should have a scope if ( - !in_array($value->getRole(), $this->roleProvider->getRolesWithoutScopes()) - && - $value->getScope() === NULL - ) { + !in_array($value->getRole(), $this->roleProvider->getRolesWithoutScopes()) + && $value->getScope() === null + ) { $this->context->buildViolation($constraint->messagePresenceRequired) - ->setParameter('%role%', $this->translator->trans($value->getRole())) - ->addViolation(); + ->setParameter('%role%', $this->translator->trans($value->getRole())) + ->addViolation(); $this->logger->debug('the role scope should have a scope, but scope is null. Violation build.'); - } elseif // if the scope should be null - ( - in_array($value->getRole(), $this->roleProvider->getRolesWithoutScopes()) - && - ! is_null($value->getScope()) - ) - { + } elseif ( + // if the scope should be null + in_array($value->getRole(), $this->roleProvider->getRolesWithoutScopes()) + && !is_null($value->getScope()) + ) { $this->context->buildViolation($constraint->messageNullRequired) - ->setParameter('%role%', $this->translator->trans($value->getRole())) - ->addViolation(); + ->setParameter('%role%', $this->translator->trans($value->getRole())) + ->addViolation(); $this->logger->debug('the role scole should not have a scope, but scope is not null. Violation build.'); - } // everything is fine ! - else { + } else { + // everything is fine ! $this->logger->debug('role scope is valid. Validation finished.'); } } - } diff --git a/src/Bundle/ChillMainBundle/Validation/Validator/UserUniqueEmailAndUsername.php b/src/Bundle/ChillMainBundle/Validation/Validator/UserUniqueEmailAndUsername.php index 0dafa0b98..3d38889d9 100644 --- a/src/Bundle/ChillMainBundle/Validation/Validator/UserUniqueEmailAndUsername.php +++ b/src/Bundle/ChillMainBundle/Validation/Validator/UserUniqueEmailAndUsername.php @@ -1,117 +1,105 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Validation\Validator; - -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Constraint; -use Chill\MainBundle\Entity\User; -use Doctrine\ORM\EntityManagerInterface; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Validation\Validator; + +use Chill\MainBundle\Entity\User; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use UnexpectedValueException; + class UserUniqueEmailAndUsername extends ConstraintValidator { /** - * * @var EntityManagerInterface */ protected $em; - + public function __construct(EntityManagerInterface $em) { $this->em = $em; } - public function validate($value, Constraint $constraint) { if (!$value instanceof User) { - throw new \UnexpectedValueException("This validation should happens " - . "only on class ".User::class); + throw new UnexpectedValueException('This validation should happens ' + . 'only on class ' . User::class); } - + if ($value->getId() !== null) { $countUsersByUsername = $this->em->createQuery( sprintf( - "SELECT COUNT(u) FROM %s u " - . "WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) " - . "AND u != :user", - User::class) + 'SELECT COUNT(u) FROM %s u ' + . 'WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) ' + . 'AND u != :user', + User::class ) + ) ->setParameter('username', $value->getUsername()) ->setParameter('user', $value) ->getSingleScalarResult(); } else { $countUsersByUsername = $this->em->createQuery( sprintf( - "SELECT COUNT(u) FROM %s u " - . "WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) ", - User::class) + 'SELECT COUNT(u) FROM %s u ' + . 'WHERE u.usernameCanonical = LOWER(UNACCENT(:username)) ', + User::class ) + ) ->setParameter('username', $value->getUsername()) ->getSingleScalarResult(); } - - if ($countUsersByUsername > 0) { + + if (0 < $countUsersByUsername) { $this->context ->buildViolation($constraint->messageDuplicateUsername) ->setParameters([ - '%username%' => $value->getUsername() + '%username%' => $value->getUsername(), ]) ->atPath('username') - ->addViolation() - ; + ->addViolation(); } - + if ($value->getId() !== null) { $countUsersByEmail = $this->em->createQuery( sprintf( - "SELECT COUNT(u) FROM %s u " - . "WHERE u.emailCanonical = LOWER(UNACCENT(:email)) " - . "AND u != :user", - User::class) + 'SELECT COUNT(u) FROM %s u ' + . 'WHERE u.emailCanonical = LOWER(UNACCENT(:email)) ' + . 'AND u != :user', + User::class ) + ) ->setParameter('email', $value->getEmail()) ->setParameter('user', $value) ->getSingleScalarResult(); } else { $countUsersByEmail = $this->em->createQuery( sprintf( - "SELECT COUNT(u) FROM %s u " - . "WHERE u.emailCanonical = LOWER(UNACCENT(:email))", - User::class) + 'SELECT COUNT(u) FROM %s u ' + . 'WHERE u.emailCanonical = LOWER(UNACCENT(:email))', + User::class ) + ) ->setParameter('email', $value->getEmail()) ->getSingleScalarResult(); } - - if ($countUsersByEmail > 0) { + + if (0 < $countUsersByEmail) { $this->context ->buildViolation($constraint->messageDuplicateEmail) ->setParameters([ - '%email%' => $value->getEmail() + '%email%' => $value->getEmail(), ]) ->atPath('email') - ->addViolation() - ; + ->addViolation(); } } } diff --git a/src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php b/src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php index 127bfad33..d5346090e 100644 --- a/src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php +++ b/src/Bundle/ChillMainBundle/Validation/Validator/ValidPhonenumber.php @@ -1,41 +1,29 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\MainBundle\Validation\Validator; - -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Constraint; -use Chill\MainBundle\Phonenumber\PhonenumberHelper; -use Psr\Log\LoggerInterface; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\MainBundle\Validation\Validator; + +use Chill\MainBundle\Phonenumber\PhonenumberHelper; +use LogicException; +use Psr\Log\LoggerInterface; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; + class ValidPhonenumber extends ConstraintValidator { + protected $logger; + /** - * * @var PhonenumberHelper */ protected $phonenumberHelper; - - protected $logger; - + public function __construct( LoggerInterface $logger, PhonenumberHelper $phonenumberHelper @@ -43,45 +31,49 @@ class ValidPhonenumber extends ConstraintValidator $this->phonenumberHelper = $phonenumberHelper; $this->logger = $logger; } - + /** - * * @param string $value * @param \Chill\MainBundle\Validation\Constraint\PhonenumberConstraint $constraint */ public function validate($value, Constraint $constraint) { - if (FALSE === $this->phonenumberHelper->isPhonenumberValidationConfigured()) { + if (false === $this->phonenumberHelper->isPhonenumberValidationConfigured()) { $this->logger->debug('[phonenumber] skipping validation due to not configured helper'); - + return; } - + if (empty($value)) { return; } - - switch($constraint->type) { + + switch ($constraint->type) { case 'landline': $isValid = $this->phonenumberHelper->isValidPhonenumberLandOrVoip($value); $message = $constraint->notLandlineMessage; + break; + case 'mobile': $isValid = $this->phonenumberHelper->isValidPhonenumberMobile($value); $message = $constraint->notMobileMessage; + break; + case 'any': $isValid = $this->phonenumberHelper->isValidPhonenumberAny($value); $message = $constraint->notValidMessage; + break; - + default: - throw new \LogicException(sprintf("This type '%s' is not implemented. " + throw new LogicException(sprintf("This type '%s' is not implemented. " . "Possible values are 'mobile', 'landline' or 'any'", $constraint->type)); } - - if (FALSE === $isValid) { - $this->context->addViolation($message, [ '%phonenumber%' => $value ]); + + if (false === $isValid) { + $this->context->addViolation($message, ['%phonenumber%' => $value]); } } } diff --git a/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistency.php b/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistency.php index 238aa1a7f..181f32c81 100644 --- a/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistency.php +++ b/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistency.php @@ -1,52 +1,41 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Validator\Constraints\Entity; use Symfony\Component\Validator\Constraint; /** - * - * * @Annotation */ class UserCircleConsistency extends Constraint { - public $message = "{{ username }} is not allowed to see entities published in this circle"; - - public $role; - public $getUserFunction = 'getUser'; - + + public $message = '{{ username }} is not allowed to see entities published in this circle'; + public $path = 'circle'; - + + public $role; + public function getDefaultOption() { return 'role'; } - + public function getRequiredOptions() { - return [ 'role' ]; + return ['role']; } - + public function getTargets() { return self::CLASS_CONSTRAINT; } - } diff --git a/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php b/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php index c8ec72b50..f77834ab4 100644 --- a/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php +++ b/src/Bundle/ChillMainBundle/Validator/Constraints/Entity/UserCircleConsistencyValidator.php @@ -1,66 +1,51 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Validator\Constraints\Entity; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -use Chill\MainBundle\Entity\HasScopeInterface; -/** - * - * - */ +use function call_user_func; + class UserCircleConsistencyValidator extends ConstraintValidator { /** - * * @var AuthorizationHelper */ protected $autorizationHelper; - - function __construct(AuthorizationHelper $autorizationHelper) + + public function __construct(AuthorizationHelper $autorizationHelper) { $this->autorizationHelper = $autorizationHelper; } - /** - * * @param object $value * @param UserCircleConsistency $constraint */ public function validate($value, Constraint $constraint) { /* @var $user \Chill\MainBundle\Entity\User */ - $user = \call_user_func([$value, $constraint->getUserFunction ]); - - if ($user === null) { + $user = call_user_func([$value, $constraint->getUserFunction]); + + if (null === $user) { return; } - - if (FALSE === $this->autorizationHelper->userHasAccess($user, $value, $constraint->role)) { + + if (false === $this->autorizationHelper->userHasAccess($user, $value, $constraint->role)) { $this->context ->buildViolation($constraint->message) ->setParameter('{{ username }}', $user->getUsername()) ->atPath($constraint->path) - ->addViolation() - ; + ->addViolation(); } } } diff --git a/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraint.php b/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraint.php index d00962e39..f2be41ddb 100644 --- a/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraint.php +++ b/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraint.php @@ -1,47 +1,37 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Validator\Constraints\Export; use Symfony\Component\Validator\Constraint; /** - * Constraint which will check the ExportElement. + * Constraint which will check the ExportElement. * * @see ExportElementConstraintValidator - * @author Julien Fastré */ class ExportElementConstraint extends Constraint { public $element; + public function getRequiredOptions() + { + return ['element']; + } + + public function getTargets() + { + return self::PROPERTY_CONSTRAINT; + } public function validatedBy() { return ExportElementConstraintValidator::class; } - - public function getRequiredOptions() - { - return array('element'); - } - - public function getTargets() - { - return self::PROPERTY_CONSTRAINT; - } } diff --git a/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraintValidator.php b/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraintValidator.php index b6a61a0b4..af1fb68f6 100644 --- a/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraintValidator.php +++ b/src/Bundle/ChillMainBundle/Validator/Constraints/Export/ExportElementConstraintValidator.php @@ -1,40 +1,30 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\MainBundle\Validator\Constraints\Export; +use Chill\MainBundle\Export\ExportElementValidatedInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -use Chill\MainBundle\Export\ExportElementValidatedInterface; /** * This validator validate the _export element_ if this element implements - * {@link ExportElementValidatedInterface}. - * - * @author Julien Fastré + * {@link ExportElementValidatedInterface}. */ class ExportElementConstraintValidator extends ConstraintValidator { public function validate($value, Constraint $constraint) - { + { if ($constraint->element instanceof ExportElementValidatedInterface) { - if ($value["enabled"] === true) { - $constraint->element->validateForm($value["form"], $this->context); - } + if (true === $value['enabled']) { + $constraint->element->validateForm($value['form'], $this->context); + } } } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20141128194409.php b/src/Bundle/ChillMainBundle/migrations/Version20141128194409.php index 2f75b9566..900712c0d 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20141128194409.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20141128194409.php @@ -1,56 +1,62 @@ addSql("CREATE TABLE Country (id INT NOT NULL, name JSON NOT NULL, countryCode VARCHAR(3) NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE centers (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE Language (id VARCHAR(255) NOT NULL, name JSON NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE group_centers (id INT NOT NULL, center_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_A14D8F3D5932F377 ON group_centers (center_id);"); - $this->addSql("CREATE TABLE groupcenter_permissionsgroup (groupcenter_id INT NOT NULL, permissionsgroup_id INT NOT NULL, PRIMARY KEY(groupcenter_id, permissionsgroup_id));"); - $this->addSql("CREATE INDEX IDX_55DFEC607EC2FA68 ON groupcenter_permissionsgroup (groupcenter_id);"); - $this->addSql("CREATE INDEX IDX_55DFEC606FA97D46 ON groupcenter_permissionsgroup (permissionsgroup_id);"); - $this->addSql("CREATE TABLE role_scopes (id INT NOT NULL, scope_id INT DEFAULT NULL, role VARCHAR(255) NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_AFF20281682B5931 ON role_scopes (scope_id);"); - $this->addSql("CREATE TABLE permission_groups (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE permissionsgroup_rolescope (permissionsgroup_id INT NOT NULL, rolescope_id INT NOT NULL, PRIMARY KEY(permissionsgroup_id, rolescope_id));"); - $this->addSql("CREATE INDEX IDX_B22441DC6FA97D46 ON permissionsgroup_rolescope (permissionsgroup_id);"); - $this->addSql("CREATE INDEX IDX_B22441DCA0AE1DB7 ON permissionsgroup_rolescope (rolescope_id);"); - $this->addSql("CREATE TABLE users (id INT NOT NULL, username VARCHAR(80) NOT NULL, password VARCHAR(255) NOT NULL, salt VARCHAR(255) DEFAULT NULL, enabled BOOLEAN NOT NULL, locked BOOLEAN NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE user_groupcenter (user_id INT NOT NULL, groupcenter_id INT NOT NULL, PRIMARY KEY(user_id, groupcenter_id));"); - $this->addSql("CREATE INDEX IDX_33FFE54AA76ED395 ON user_groupcenter (user_id);"); - $this->addSql("CREATE INDEX IDX_33FFE54A7EC2FA68 ON user_groupcenter (groupcenter_id);"); - $this->addSql("CREATE TABLE scopes (id INT NOT NULL, name JSON NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE SEQUENCE Country_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE centers_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE group_centers_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE role_scopes_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE permission_groups_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE users_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE scopes_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("ALTER TABLE group_centers ADD CONSTRAINT FK_A14D8F3D5932F377 FOREIGN KEY (center_id) REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT FK_55DFEC607EC2FA68 FOREIGN KEY (groupcenter_id) REFERENCES group_centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT FK_55DFEC606FA97D46 FOREIGN KEY (permissionsgroup_id) REFERENCES permission_groups (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE role_scopes ADD CONSTRAINT FK_AFF20281682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE permissionsgroup_rolescope ADD CONSTRAINT FK_B22441DC6FA97D46 FOREIGN KEY (permissionsgroup_id) REFERENCES permission_groups (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE permissionsgroup_rolescope ADD CONSTRAINT FK_B22441DCA0AE1DB7 FOREIGN KEY (rolescope_id) REFERENCES role_scopes (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE user_groupcenter ADD CONSTRAINT FK_33FFE54AA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE user_groupcenter ADD CONSTRAINT FK_33FFE54A7EC2FA68 FOREIGN KEY (groupcenter_id) REFERENCES group_centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs + } + public function up(Schema $schema): void + { + $this->addSql('CREATE TABLE Country (id INT NOT NULL, name JSON NOT NULL, countryCode VARCHAR(3) NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE centers (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE Language (id VARCHAR(255) NOT NULL, name JSON NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE group_centers (id INT NOT NULL, center_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_A14D8F3D5932F377 ON group_centers (center_id);'); + $this->addSql('CREATE TABLE groupcenter_permissionsgroup (groupcenter_id INT NOT NULL, permissionsgroup_id INT NOT NULL, PRIMARY KEY(groupcenter_id, permissionsgroup_id));'); + $this->addSql('CREATE INDEX IDX_55DFEC607EC2FA68 ON groupcenter_permissionsgroup (groupcenter_id);'); + $this->addSql('CREATE INDEX IDX_55DFEC606FA97D46 ON groupcenter_permissionsgroup (permissionsgroup_id);'); + $this->addSql('CREATE TABLE role_scopes (id INT NOT NULL, scope_id INT DEFAULT NULL, role VARCHAR(255) NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_AFF20281682B5931 ON role_scopes (scope_id);'); + $this->addSql('CREATE TABLE permission_groups (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE permissionsgroup_rolescope (permissionsgroup_id INT NOT NULL, rolescope_id INT NOT NULL, PRIMARY KEY(permissionsgroup_id, rolescope_id));'); + $this->addSql('CREATE INDEX IDX_B22441DC6FA97D46 ON permissionsgroup_rolescope (permissionsgroup_id);'); + $this->addSql('CREATE INDEX IDX_B22441DCA0AE1DB7 ON permissionsgroup_rolescope (rolescope_id);'); + $this->addSql('CREATE TABLE users (id INT NOT NULL, username VARCHAR(80) NOT NULL, password VARCHAR(255) NOT NULL, salt VARCHAR(255) DEFAULT NULL, enabled BOOLEAN NOT NULL, locked BOOLEAN NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE user_groupcenter (user_id INT NOT NULL, groupcenter_id INT NOT NULL, PRIMARY KEY(user_id, groupcenter_id));'); + $this->addSql('CREATE INDEX IDX_33FFE54AA76ED395 ON user_groupcenter (user_id);'); + $this->addSql('CREATE INDEX IDX_33FFE54A7EC2FA68 ON user_groupcenter (groupcenter_id);'); + $this->addSql('CREATE TABLE scopes (id INT NOT NULL, name JSON NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE SEQUENCE Country_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE centers_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE group_centers_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE role_scopes_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE permission_groups_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE users_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE scopes_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('ALTER TABLE group_centers ADD CONSTRAINT FK_A14D8F3D5932F377 FOREIGN KEY (center_id) REFERENCES centers (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT FK_55DFEC607EC2FA68 FOREIGN KEY (groupcenter_id) REFERENCES group_centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT FK_55DFEC606FA97D46 FOREIGN KEY (permissionsgroup_id) REFERENCES permission_groups (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE role_scopes ADD CONSTRAINT FK_AFF20281682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE permissionsgroup_rolescope ADD CONSTRAINT FK_B22441DC6FA97D46 FOREIGN KEY (permissionsgroup_id) REFERENCES permission_groups (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE permissionsgroup_rolescope ADD CONSTRAINT FK_B22441DCA0AE1DB7 FOREIGN KEY (rolescope_id) REFERENCES role_scopes (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE user_groupcenter ADD CONSTRAINT FK_33FFE54AA76ED395 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE user_groupcenter ADD CONSTRAINT FK_33FFE54A7EC2FA68 FOREIGN KEY (groupcenter_id) REFERENCES group_centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20150821105642.php b/src/Bundle/ChillMainBundle/migrations/Version20150821105642.php index ffc3055ad..846922d8f 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20150821105642.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20150821105642.php @@ -1,33 +1,136 @@ GroupCenter * to - * ManyToOne : a GroupCenter can have only one PermissionGroup - * - * @link https://redmine.champs-libres.coop/issues/578 The issue describing the move + * ManyToOne : a GroupCenter can have only one PermissionGroup. + * + * @see https://redmine.champs-libres.coop/issues/578 The issue describing the move */ -class Version20150821105642 extends AbstractMigration implements - \Symfony\Component\DependencyInjection\ContainerAwareInterface +class Version20150821105642 extends AbstractMigration implements \Symfony\Component\DependencyInjection\ContainerAwareInterface { /** - * * @var ContainerInterface */ private $container; - - /** - * @param Schema $schema - */ + public function down(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE group_centers DROP CONSTRAINT FK_A14D8F3D447BBB3B'); + $this->addSql('DROP INDEX IDX_A14D8F3D447BBB3B'); + $this->addSql('ALTER TABLE group_centers DROP permissionGroup_id'); + } + + public function postUp(Schema $schema): void + { + /* + * Before the upgrade to symfony version 4, this code worked. + * + * But it doesn't work any more after the migration and currently this + * code should note be necessary. + * + * This code is kept for reference, and may be re-activated if needed, but + * the probability that this will happens is near 0 + */ + return; + //transform data from groupcenter_permissionsgroup table + $em = $this->container->get('doctrine.orm.entity_manager'); + + //get all existing associations + $rsm = new ResultSetMapping(); + $rsm->addScalarResult('groupcenter_id', 'groupcenter_id'); + $rsm->addScalarResult('permissionsgroup_id', 'permissionsgroup_id'); + + $groupPermissionsAssociations = $em->createNativeQuery( + 'SELECT groupcenter_id, permissionsgroup_id ' + . 'FROM groupcenter_permissionsgroup', + $rsm + ) + ->getScalarResult(); + + //update + foreach ($groupPermissionsAssociations as $groupPermissionAssociation) { + //get the corresponding groupCenter + $rsmGroupCenter = new ResultSetMapping(); + $rsmGroupCenter->addScalarResult('id', 'id'); + $rsmGroupCenter->addScalarResult('permissionsGroup_id', 'permissionsGroup_id'); + $rsmGroupCenter->addScalarResult('center_id', 'center_id'); + + $groupCenters = $em->createNativeQuery( + 'SELECT id, permissionsGroup_id, center_id ' + . 'FROM group_centers ' + . 'WHERE id = :groupcenter_id AND permissionsGroup_id IS NULL', + $rsmGroupCenter + ) + ->setParameter('groupcenter_id', $groupPermissionAssociation['groupcenter_id']) + ->getResult(); + + if (count($groupCenters) === 1) { + // we have to update this group with the current association + $em->getConnection()->executeUpdate( + 'UPDATE group_centers ' + . 'SET permissionsGroup_id = ? ' + . 'WHERE id = ?', + [ + $groupPermissionAssociation['permissionsgroup_id'], + $groupPermissionAssociation['groupcenter_id'], ] + ); + } elseif (count($groupCenters) === 0) { + // the association was multiple. We have to create a new group_center + $rsmNewId = new ResultSetMapping(); + $rsmNewId->addScalarResult('new_id', 'new_id'); + $newId = $em->createNativeQuery( + "select nextval('group_centers_id_seq') as new_id", + $rsmNewId + ) + ->getSingleScalarResult(); + + $em->getConnection()->insert('group_centers', [ + 'id' => $newId, + 'center_id' => $group_center['center_id'], + 'permissionsGroup_id' => $groupPermissionAssociation['permissionsgroup_id'], + ]); + + // we have to link existing users to new created groupcenter + $em->getConnection()->executeQuery('INSERT INTO user_groupcenter ' + . '(user_id, groupcenter_id) SELECT user_id, ' . $newId . ' ' + . 'FROM user_groupcenter WHERE groupcenter_id = ' + . $groupPermissionAssociation['groupcenter_id']); + } else { + throw new RuntimeException('Error in the data : we should not have two groupCenter ' + . 'with the same id !'); + } + } + } + + public function setContainer(?ContainerInterface $container = null) + { + if (null === $container) { + throw new RuntimeException('Container is not provided. This migration ' + . 'need container to set a default center'); + } + + $this->container = $container; + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -36,110 +139,5 @@ class Version20150821105642 extends AbstractMigration implements $this->addSql('ALTER TABLE group_centers ADD permissionsGroup_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE group_centers ADD CONSTRAINT FK_A14D8F3D447BBB3B FOREIGN KEY (permissionsGroup_id) REFERENCES permission_groups (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_A14D8F3D447BBB3B ON group_centers (permissionsGroup_id)'); - } - - public function postUp(Schema $schema): void - { - /* - * Before the upgrade to symfony version 4, this code worked. - * - * But it doesn't work any more after the migration and currently this - * code should note be necessary. - * - * This code is kept for reference, and may be re-activated if needed, but - * the probability that this will happens is near 0 - */ - return; - - - //transform data from groupcenter_permissionsgroup table - $em = $this->container->get('doctrine.orm.entity_manager'); - - //get all existing associations - $rsm = new ResultSetMapping(); - $rsm->addScalarResult('groupcenter_id', 'groupcenter_id'); - $rsm->addScalarResult('permissionsgroup_id', 'permissionsgroup_id'); - - $groupPermissionsAssociations = $em->createNativeQuery( - "SELECT groupcenter_id, permissionsgroup_id " - . "FROM groupcenter_permissionsgroup", - $rsm - ) - ->getScalarResult(); - - //update - foreach ($groupPermissionsAssociations as $groupPermissionAssociation) { - //get the corresponding groupCenter - $rsmGroupCenter = new ResultSetMapping(); - $rsmGroupCenter->addScalarResult('id', 'id'); - $rsmGroupCenter->addScalarResult('permissionsGroup_id', 'permissionsGroup_id'); - $rsmGroupCenter->addScalarResult('center_id', 'center_id'); - - $groupCenters = $em->createNativeQuery("SELECT id, permissionsGroup_id, center_id " - . "FROM group_centers " - . "WHERE id = :groupcenter_id AND permissionsGroup_id IS NULL", - $rsmGroupCenter) - ->setParameter('groupcenter_id', $groupPermissionAssociation['groupcenter_id']) - ->getResult(); - - if (count($groupCenters) === 1) { - // we have to update this group with the current association - $em->getConnection()->executeUpdate("UPDATE group_centers " - . "SET permissionsGroup_id = ? " - . "WHERE id = ?", array( - $groupPermissionAssociation['permissionsgroup_id'], - $groupPermissionAssociation['groupcenter_id']) - ); - } elseif (count($groupCenters) === 0) { - // the association was multiple. We have to create a new group_center - $rsmNewId = new ResultSetMapping(); - $rsmNewId->addScalarResult('new_id', 'new_id'); - $newId = $em->createNativeQuery("select nextval('group_centers_id_seq') as new_id", - $rsmNewId) - ->getSingleScalarResult(); - - $em->getConnection()->insert("group_centers", array( - 'id' => $newId, - 'center_id' => $group_center['center_id'], - 'permissionsGroup_id' => $groupPermissionAssociation['permissionsgroup_id'] - )); - - // we have to link existing users to new created groupcenter - $em->getConnection()->executeQuery('INSERT INTO user_groupcenter ' - . '(user_id, groupcenter_id) SELECT user_id, '.$newId.' ' - . 'FROM user_groupcenter WHERE groupcenter_id = ' - .$groupPermissionAssociation['groupcenter_id']); - } else { - throw new \RuntimeException("Error in the data : we should not have two groupCenter " - . "with the same id !"); - } - } - - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE group_centers DROP CONSTRAINT FK_A14D8F3D447BBB3B'); - $this->addSql('DROP INDEX IDX_A14D8F3D447BBB3B'); - $this->addSql('ALTER TABLE group_centers DROP permissionGroup_id'); - - } - - public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null) - { - if ($container === NULL) { - throw new \RuntimeException('Container is not provided. This migration ' - . 'need container to set a default center'); - } - - $this->container = $container; - } - } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20150821122935.php b/src/Bundle/ChillMainBundle/migrations/Version20150821122935.php index f20b9d927..dce99a7a2 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20150821122935.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20150821122935.php @@ -1,39 +1,37 @@ addSql('DROP TABLE groupcenter_permissionsgroup'); - $this->addSql('ALTER TABLE group_centers ALTER permissionsGroup_id SET NOT NULL'); - - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->addSql('ALTER TABLE group_centers ALTER permissionsGroup_id SET DEFAULT NULL'); $this->addSql('CREATE TABLE groupcenter_permissionsgroup (groupcenter_id INT NOT NULL, permissionsgroup_id INT NOT NULL, PRIMARY KEY(groupcenter_id, permissionsgroup_id))'); $this->addSql('CREATE INDEX idx_55dfec607ec2fa68 ON groupcenter_permissionsgroup (groupcenter_id)'); $this->addSql('CREATE INDEX idx_55dfec606fa97d46 ON groupcenter_permissionsgroup (permissionsgroup_id)'); - + $this->addSql('ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT fk_55dfec607ec2fa68 FOREIGN KEY (groupcenter_id) REFERENCES group_centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE groupcenter_permissionsgroup ADD CONSTRAINT fk_55dfec606fa97d46 FOREIGN KEY (permissionsgroup_id) REFERENCES permission_groups (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + } + public function up(Schema $schema): void + { + $this->addSql('DROP TABLE groupcenter_permissionsgroup'); + $this->addSql('ALTER TABLE group_centers ALTER permissionsGroup_id SET NOT NULL'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20160310122322.php b/src/Bundle/ChillMainBundle/migrations/Version20160310122322.php index 25220555b..100be7151 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20160310122322.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20160310122322.php @@ -1,18 +1,34 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_main_address ' + . 'DROP CONSTRAINT FK_165051F6EECBFDF1'); + $this->addSql('DROP SEQUENCE chill_main_address_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_main_postal_code_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_address'); + $this->addSql('DROP TABLE chill_main_postal_code'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -46,21 +62,5 @@ class Version20160310122322 extends AbstractMigration . 'FOREIGN KEY (country_id) ' . 'REFERENCES Country (id) ' . 'NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_main_address ' - . 'DROP CONSTRAINT FK_165051F6EECBFDF1'); - $this->addSql('DROP SEQUENCE chill_main_address_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_main_postal_code_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_main_address'); - $this->addSql('DROP TABLE chill_main_postal_code'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20180703191509.php b/src/Bundle/ChillMainBundle/migrations/Version20180703191509.php index 2546018c0..a15ee7c8c 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20180703191509.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20180703191509.php @@ -1,15 +1,32 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP INDEX search_name_code'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -17,17 +34,8 @@ final class Version20180703191509 extends AbstractMigration try { $this->addSql('CREATE EXTENSION IF NOT EXISTS pg_trgm'); $this->addSql('CREATE INDEX search_name_code ON chill_main_postal_code USING GIN (LOWER(code) gin_trgm_ops, LOWER(label) gin_trgm_ops)'); - } catch (\Exception $e) { - $this->skipIf(true, "Could not create extension pg_trgm"); + } catch (Exception $e) { + $this->skipIf(true, 'Could not create extension pg_trgm'); } - - } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP INDEX search_name_code'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20180709181423.php b/src/Bundle/ChillMainBundle/migrations/Version20180709181423.php index 3a23657f9..fe1b65a30 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20180709181423.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20180709181423.php @@ -1,16 +1,40 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP INDEX UNIQ_1483A5E9F5A5DC32'); + $this->addSql('DROP INDEX UNIQ_1483A5E9885281E'); + $this->addSql('ALTER TABLE users DROP usernameCanonical'); + $this->addSql('ALTER TABLE users DROP email'); + $this->addSql('ALTER TABLE users DROP emailCanonical'); + $this->addSql('DROP TRIGGER canonicalize_user_on_insert ON users'); + $this->addSql('DROP FUNCTION canonicalize_user_on_insert()'); + $this->addSql('DROP TRIGGER canonicalize_user_on_update ON users'); + $this->addSql('DROP FUNCTION canonicalize_user_on_update()'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -23,65 +47,53 @@ final class Version20180709181423 extends AbstractMigration $this->addSql('ALTER TABLE users ADD emailCanonical VARCHAR(150) DEFAULT NULL'); $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E9F5A5DC32 ON users (usernameCanonical)'); $this->addSql('CREATE UNIQUE INDEX UNIQ_1483A5E9885281E ON users (emailCanonical)'); - - $this->addSql(<<<'SQL' - CREATE OR REPLACE FUNCTION canonicalize_user_on_update() RETURNS TRIGGER AS - $BODY$ - BEGIN - IF NEW.username <> OLD.username OR NEW.email <> OLD.email OR OLD.emailcanonical IS NULL OR OLD.usernamecanonical IS NULL THEN - UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id; - END IF; - RETURN NEW; - END; - $BODY$ LANGUAGE PLPGSQL -SQL + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION canonicalize_user_on_update() RETURNS TRIGGER AS + $BODY$ + BEGIN + IF NEW.username <> OLD.username OR NEW.email <> OLD.email OR OLD.emailcanonical IS NULL OR OLD.usernamecanonical IS NULL THEN + UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id; + END IF; + + RETURN NEW; + END; + $BODY$ LANGUAGE PLPGSQL + SQL ); - $this->addSql(<<addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_user_on_update + AFTER UPDATE + ON users + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_user_on_update(); + SQL ); - $this->addSql(<<<'SQL' - CREATE OR REPLACE FUNCTION canonicalize_user_on_insert() RETURNS TRIGGER AS - $BODY$ - BEGIN - UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id; + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION canonicalize_user_on_insert() RETURNS TRIGGER AS + $BODY$ + BEGIN + UPDATE users SET usernamecanonical=LOWER(UNACCENT(NEW.username)), emailcanonical=LOWER(UNACCENT(NEW.email)) WHERE id=NEW.id; - RETURN NEW; - END; - $BODY$ LANGUAGE PLPGSQL; -SQL + RETURN NEW; + END; + $BODY$ LANGUAGE PLPGSQL; + SQL ); - $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP INDEX UNIQ_1483A5E9F5A5DC32'); - $this->addSql('DROP INDEX UNIQ_1483A5E9885281E'); - $this->addSql('ALTER TABLE users DROP usernameCanonical'); - $this->addSql('ALTER TABLE users DROP email'); - $this->addSql('ALTER TABLE users DROP emailCanonical'); - $this->addSql('DROP TRIGGER canonicalize_user_on_insert ON users'); - $this->addSql('DROP FUNCTION canonicalize_user_on_insert()'); - $this->addSql('DROP TRIGGER canonicalize_user_on_update ON users'); - $this->addSql('DROP FUNCTION canonicalize_user_on_update()'); - + $this->addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_user_on_insert + AFTER INSERT + ON users + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_user_on_insert(); + SQL + ); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20180905101426.php b/src/Bundle/ChillMainBundle/migrations/Version20180905101426.php index 841a68750..e56936aed 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20180905101426.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20180905101426.php @@ -1,4 +1,13 @@ -addSql('ALTER TABLE permission_groups DROP COLUMN flags'); + $this->addSql('ALTER TABLE group_centers ALTER permissionsgroup_id SET DEFAULT NULL'); + } + public function up(Schema $schema): void { $this->addSql('ALTER TABLE permission_groups ADD flags JSONB DEFAULT \'[]\' NOT NULL'); $this->addSql('ALTER TABLE group_centers ALTER permissionsgroup_id DROP NOT NULL'); - - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE permission_groups DROP COLUMN flags'); - $this->addSql('ALTER TABLE group_centers ALTER permissionsgroup_id SET DEFAULT NULL'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20180911093642.php b/src/Bundle/ChillMainBundle/migrations/Version20180911093642.php index 6ff24bc5a..7582acdf5 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20180911093642.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20180911093642.php @@ -1,4 +1,13 @@ -addSql("DROP TRIGGER canonicalize_user_on_update ON users"); - - $this->addSql(<<addSql("DROP TRIGGER canonicalize_user_on_update ON users"); - - $this->addSql(<<addSql('DROP TRIGGER canonicalize_user_on_update ON users'); + $this->addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_user_on_update + AFTER UPDATE + ON users + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_user_on_update(); + SQL + ); + } + + public function up(Schema $schema): void + { + $this->addSql('DROP TRIGGER canonicalize_user_on_update ON users'); + + $this->addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_user_on_update + AFTER UPDATE + ON users + FOR EACH ROW + WHEN (pg_trigger_depth() = 0) + EXECUTE PROCEDURE canonicalize_user_on_update(); + SQL + ); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20200422122715.php b/src/Bundle/ChillMainBundle/migrations/Version20200422122715.php index 3449e5f28..95a9abe51 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20200422122715.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20200422122715.php @@ -1,4 +1,13 @@ -addSql('ALTER TABLE chill_main_address ADD isNoAddress BOOLEAN NOT NULL DEFAULT FALSE'); - } - public function down(Schema $schema): void { $this->addSql('ALTER TABLE chill_main_address DROP isNoAddress'); } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_main_address ADD isNoAddress BOOLEAN NOT NULL DEFAULT FALSE'); + } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php b/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php index 5f1fb6869..4f3e69167 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210304085819.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE users DROP attributes'); + } + + public function getDescription(): string { return ''; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('ALTER TABLE users ADD attributes JSONB DEFAULT NULL'); $this->addSql('COMMENT ON COLUMN users.attributes IS \'(DC2Type:json_array)\''); } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE users DROP attributes'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php b/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php index fa4f001bb..3e5d17a4a 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210308111926.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_main_address ADD customs JSONB DEFAULT \'[]\''); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->addSql('ALTER TABLE chill_main_address DROP customs'); } - + public function getDescription(): string { - return "Add custom data in addresses"; + return 'Add custom data in addresses'; + } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_main_address ADD customs JSONB DEFAULT \'[]\''); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210414091001.php b/src/Bundle/ChillMainBundle/migrations/Version20210414091001.php index db207c594..3eaa4630d 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210414091001.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210414091001.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('CREATE EXTENSION IF NOT EXISTS postgis;'); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -27,6 +28,13 @@ final class Version20210414091001 extends AbstractMigration public function getDescription(): string { - return "Enable the postgis extension in public schema"; + return 'Enable the postgis extension in public schema'; + } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE EXTENSION IF NOT EXISTS postgis;'); } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210420115006.php b/src/Bundle/ChillMainBundle/migrations/Version20210420115006.php index 79dea4853..b0b281d06 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210420115006.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210420115006.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress1 TO street;'); - $this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress2 TO streetNumber;'); - $this->addSql('ALTER TABLE chill_main_address ADD floor VARCHAR(16) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD corridor VARCHAR(16) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD steps VARCHAR(16) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD buildingName VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD flat VARCHAR(16) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD distribution VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD extra VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD validTo DATE DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_main_address ADD point geometry(POINT,4326) DEFAULT NULL'); - } - - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE chill_main_address RENAME COLUMN street TO streetaddress1;'); $this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetNumber TO streetaddress2;'); @@ -47,4 +33,24 @@ final class Version20210420115006 extends AbstractMigration $this->addSql('ALTER TABLE chill_main_address DROP validTo'); $this->addSql('ALTER TABLE chill_main_address DROP point'); } + + public function getDescription(): string + { + return 'Add a Point data type and modify the Address entity'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress1 TO street;'); + $this->addSql('ALTER TABLE chill_main_address RENAME COLUMN streetaddress2 TO streetNumber;'); + $this->addSql('ALTER TABLE chill_main_address ADD floor VARCHAR(16) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD corridor VARCHAR(16) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD steps VARCHAR(16) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD buildingName VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD flat VARCHAR(16) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD distribution VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD extra VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD validTo DATE DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_main_address ADD point geometry(POINT,4326) DEFAULT NULL'); + } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210503085107.php b/src/Bundle/ChillMainBundle/migrations/Version20210503085107.php index f693777a0..0f664e2b2 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210503085107.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210503085107.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_main_address_reference_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_main_address_reference'); + } + public function getDescription(): string { return 'Add a AddressReference table for storing authoritative address data'; @@ -24,10 +37,4 @@ final class Version20210503085107 extends AbstractMigration $this->addSql('CREATE INDEX IDX_CA6C1BD7EECBFDF1 ON chill_main_address_reference (postcode_id)'); $this->addSql('ALTER TABLE chill_main_address_reference ADD CONSTRAINT FK_CA6C1BD7EECBFDF1 FOREIGN KEY (postcode_id) REFERENCES chill_main_postal_code (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP SEQUENCE chill_main_address_reference_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_main_address_reference'); - } } diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210505153727.php b/src/Bundle/ChillMainBundle/migrations/Version20210505153727.php index 42161ba84..34c3c10b9 100644 --- a/src/Bundle/ChillMainBundle/migrations/Version20210505153727.php +++ b/src/Bundle/ChillMainBundle/migrations/Version20210505153727.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9'); + $this->addSql('DROP INDEX IDX_165051F6114B8DD9'); + $this->addSql('ALTER TABLE chill_main_address DROP linkedToThirdParty_id'); + $this->addSql('DROP TABLE IF EXISTS chill_main_address_legacy'); + $this->addSql(' + UPDATE chill_main_address + SET validto = null; + '); + } + public function getDescription(): string { return 'Add linkedToThirdParty field to Address'; @@ -43,16 +62,4 @@ final class Version20210505153727 extends AbstractMigration ); '); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F6114B8DD9'); - $this->addSql('DROP INDEX IDX_165051F6114B8DD9'); - $this->addSql('ALTER TABLE chill_main_address DROP linkedToThirdParty_id'); - $this->addSql('DROP TABLE IF EXISTS chill_main_address_legacy'); - $this->addSql(' - UPDATE chill_main_address - SET validto = null; - '); - } } diff --git a/src/Bundle/ChillPersonBundle/Actions/ActionEvent.php b/src/Bundle/ChillPersonBundle/Actions/ActionEvent.php index 5ac3055cb..da0071b09 100644 --- a/src/Bundle/ChillPersonBundle/Actions/ActionEvent.php +++ b/src/Bundle/ChillPersonBundle/Actions/ActionEvent.php @@ -1,73 +1,61 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Actions; use Symfony\Component\EventDispatcher\Event; /** * Event triggered when an entity attached to a person is removed. - * - * */ class ActionEvent extends Event { - const DELETE = 'CHILL_PERSON.DELETE_ASSOCIATED_ENTITY'; - const MOVE = 'CHILL_PERSON.MOVE_ASSOCIATED_ENTITY'; - + public const DELETE = 'CHILL_PERSON.DELETE_ASSOCIATED_ENTITY'; + + public const MOVE = 'CHILL_PERSON.MOVE_ASSOCIATED_ENTITY'; + /** - * - * @var int - */ - protected $personId; - - /** - * the FQDN class name as recorded in doctrine + * the FQDN class name as recorded in doctrine. * * @var string */ protected $entity; - + /** - * an array of key value data to describe the movement + * an array of key value data to describe the movement. * * @var array */ protected $metadata; - + /** - * the sql statement - * - * @var string + * @var int */ - protected $sqlStatement; - + protected $personId; + /** - * - * @var string[] - */ - protected $preSql = []; - - /** - * * @var string[] */ protected $postSql = []; - + + /** + * @var string[] + */ + protected $preSql = []; + + /** + * the sql statement. + * + * @var string + */ + protected $sqlStatement; + public function __construct($personId, $entity, $sqlStatement, $metadata = []) { $this->personId = $personId; @@ -77,21 +65,17 @@ class ActionEvent extends Event } /** - * - * @return string[] + * Add Sql which will be executed **after** the delete statement. + * + * @param type $postSql + * + * @return $this */ - public function getPreSql(): array + public function addPostSql(string $postSql) { - return $this->preSql; - } + $this->postSql[] = $postSql; - /** - * - * @return string[] - */ - public function getPostSql(): array - { - return $this->postSql; + return $this; } /* @@ -100,19 +84,21 @@ class ActionEvent extends Event public function addPreSql(string $preSql) { $this->preSql[] = $preSql; + return $this; } /** - * Add Sql which will be executed **after** the delete statement - * - * @param type $postSql - * @return $this + * get the entity name, as recorded in doctrine. */ - public function addPostSql(string $postSql) + public function getEntity(): string { - $this->postSql[] = $postSql; - return $this; + return $this->entity; + } + + public function getMetadata() + { + return $this->metadata; } public function getPersonId(): int @@ -121,23 +107,23 @@ class ActionEvent extends Event } /** - * get the entity name, as recorded in doctrine - * - * @return string + * @return string[] */ - public function getEntity(): string + public function getPostSql(): array { - return $this->entity; + return $this->postSql; } - + + /** + * @return string[] + */ + public function getPreSql(): array + { + return $this->preSql; + } + public function getSqlStatement() { return $this->sqlStatement; } - - public function getMetadata() - { - return $this->metadata; - } - } diff --git a/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php b/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php index bb5d9bdac..bfbc4f36d 100644 --- a/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php +++ b/src/Bundle/ChillPersonBundle/Actions/Remove/PersonMove.php @@ -1,54 +1,46 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\PersonBundle\Actions\Remove; - -use Doctrine\ORM\EntityManagerInterface; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\ORM\Mapping\ClassMetadata; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Chill\PersonBundle\Actions\ActionEvent; /** - * Move or delete entities associated to a person to a new one, and delete the - * old person. The data associated to a person (birthdate, name, ...) are left - * untouched on the "new one". - * - * See `getSql` for details. - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\PersonBundle\Actions\Remove; + +use Chill\PersonBundle\Actions\ActionEvent; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +use function array_merge; +use function implode; +use function in_array; + +/** + * Move or delete entities associated to a person to a new one, and delete the + * old person. The data associated to a person (birthdate, name, ...) are left + * untouched on the "new one". + * + * See `getSql` for details. */ class PersonMove { /** - * * @var EntityManagerInterface */ protected $em; - + /** - * * @var EventDispatcherInterface */ protected $eventDispatcher; - + public function __construct( - EntityManagerInterface $em, + EntityManagerInterface $em, EventDispatcherInterface $eventDispatcher ) { $this->em = $em; @@ -56,128 +48,136 @@ class PersonMove } /** - * Return the sql used to move or delete entities associated to a person to - * a new one, and delete the old person. The data associated to a person + * Return the sql used to move or delete entities associated to a person to + * a new one, and delete the old person. The data associated to a person * (birthdate, name, ...) are left untouched on the "new one". - * - * The accompanying periods associated to a person are always removed. The other + * + * The accompanying periods associated to a person are always removed. The other * associated entity are updated: the new person id is associated to the entity. - * + * * Optionnaly, you can ask for removing entity by passing them in $deleteEntities - * parameters. - * + * parameters. + * * The following events are triggered: * - `'CHILL_PERSON.DELETE_ASSOCIATED_ENTITY'` is triggered when an entity * will be removed ; * - `'CHILL_PERSON.MOVE_ASSOCIATED_ENTITY'` is triggered when an entity * will be moved ; - * + * * Those events have the following metadata: - * + * * - 'original_action' : always 'move' ; * - 'to': the person id to move ; - * - * @param Person $from - * @param Person $to - * @param array $deleteEntities + * * @return type */ public function getSQL(Person $from, Person $to, array $deleteEntities = []) { $sqls = []; - $toDelete = \array_merge($deleteEntities, $this->getDeleteEntities()); - + $toDelete = array_merge($deleteEntities, $this->getDeleteEntities()); + foreach ($this->em->getMetadataFactory()->getAllMetadata() as $metadata) { if ($metadata->isMappedSuperclass) { continue; } - + foreach ($metadata->getAssociationMappings() as $field => $mapping) { - if ($mapping['targetEntity'] === Person::class) { - if (\in_array($metadata->getName(), $toDelete)) { + if (Person::class === $mapping['targetEntity']) { + if (in_array($metadata->getName(), $toDelete)) { $sql = $this->createDeleteSQL($metadata, $from, $field); - $event = new ActionEvent($from->getId(), $metadata->getName(), $sql, - ['to' => $to->getId(), 'original_action' => 'move']); + $event = new ActionEvent( + $from->getId(), + $metadata->getName(), + $sql, + ['to' => $to->getId(), 'original_action' => 'move'] + ); $this->eventDispatcher->dispatch(ActionEvent::DELETE, $event); - } else { $sql = $this->createMoveSQL($metadata, $from, $to, $field); - $event = new ActionEvent($from->getId(), $metadata->getName(), $sql, - ['to' => $to->getId(), 'original_action' => 'move']); + $event = new ActionEvent( + $from->getId(), + $metadata->getName(), + $sql, + ['to' => $to->getId(), 'original_action' => 'move'] + ); $this->eventDispatcher->dispatch(ActionEvent::MOVE, $event); } - $sqls = \array_merge($sqls, $event->getPreSql(), [$event->getSqlStatement()], $event->getPostSql()); + $sqls = array_merge($sqls, $event->getPreSql(), [$event->getSqlStatement()], $event->getPostSql()); } } } - + $personMetadata = $this->em->getClassMetadata(Person::class); - $sqls[] = sprintf("DELETE FROM %s WHERE id = %d", + $sqls[] = sprintf( + 'DELETE FROM %s WHERE id = %d', $this->getTableName($personMetadata), - $from->getId()); - + $from->getId() + ); + return $sqls ?? []; } - - protected function createMoveSQL(ClassMetadata $metadata, Person $from, Person $to, $field): string - { - $mapping = $metadata->getAssociationMapping($field); - - // Set part of the query, aka in "UPDATE table SET " - $sets = []; - foreach ($mapping["joinColumns"] as $columns) { - $sets[] = sprintf("%s = %d", $columns["name"], $to->getId()); - } - - $conditions = []; - foreach ($mapping["joinColumns"] as $columns) { - $conditions[] = sprintf("%s = %d", $columns["name"], $from->getId()); - } - - return \sprintf("UPDATE %s SET %s WHERE %s", - $this->getTableName($metadata), - \implode(" ", $sets), - \implode(" AND ", $conditions) - ); - } - + protected function createDeleteSQL(ClassMetadata $metadata, Person $from, $field): string { $mapping = $metadata->getAssociationMapping($field); - + $conditions = []; - foreach ($mapping["joinColumns"] as $columns) { - $conditions[] = sprintf("%s = %d", $columns["name"], $from->getId()); + + foreach ($mapping['joinColumns'] as $columns) { + $conditions[] = sprintf('%s = %d', $columns['name'], $from->getId()); } - - return \sprintf("DELETE FROM %s WHERE %s", + + return \sprintf( + 'DELETE FROM %s WHERE %s', $this->getTableName($metadata), - \implode(" AND ", $conditions) - ); + implode(' AND ', $conditions) + ); } - + + protected function createMoveSQL(ClassMetadata $metadata, Person $from, Person $to, $field): string + { + $mapping = $metadata->getAssociationMapping($field); + + // Set part of the query, aka in "UPDATE table SET " + $sets = []; + + foreach ($mapping['joinColumns'] as $columns) { + $sets[] = sprintf('%s = %d', $columns['name'], $to->getId()); + } + + $conditions = []; + + foreach ($mapping['joinColumns'] as $columns) { + $conditions[] = sprintf('%s = %d', $columns['name'], $from->getId()); + } + + return \sprintf( + 'UPDATE %s SET %s WHERE %s', + $this->getTableName($metadata), + implode(' ', $sets), + implode(' AND ', $conditions) + ); + } + /** - * return an array of classes where entities should be deleted - * instead of moved - * - * @return array + * return an array of classes where entities should be deleted + * instead of moved. */ protected function getDeleteEntities(): array { return [ - AccompanyingPeriod::class + AccompanyingPeriod::class, ]; } - + /** - * get the full table name with schema if it does exists + * get the full table name with schema if it does exists. */ private function getTableName(ClassMetadata $metadata): string { - return empty($metadata->getSchemaName()) ? - $metadata->getTableName() : - $metadata->getSchemaName().".".$metadata->getTableName(); + return empty($metadata->getSchemaName()) ? + $metadata->getTableName() : + $metadata->getSchemaName() . '.' . $metadata->getTableName(); } - } diff --git a/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php b/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php index 549792e51..19dfc89a8 100644 --- a/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php +++ b/src/Bundle/ChillPersonBundle/CRUD/Controller/EntityPersonCRUDController.php @@ -1,113 +1,126 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\CRUD\Controller; use Chill\MainBundle\CRUD\Controller\CRUDController; -use Symfony\Component\HttpFoundation\Request; use Chill\PersonBundle\Entity\Person; use Doctrine\ORM\QueryBuilder; +use Exception; +use Symfony\Component\HttpFoundation\Request; + +use function array_merge; /** * Class EntityPersonCRUDController - * CRUD Controller for entities attached to a Person - * - * @package Chill\PersonBundle\CRUD\Controller + * CRUD Controller for entities attached to a Person. */ class EntityPersonCRUDController extends CRUDController { /** - * Extract the person from the request - * - * the person parameter will be `person_id` and must be + * Override the base method to add a filtering step to a person. + * + * @return QueryBuilder + */ + protected function buildQueryEntities(string $action, Request $request) + { + $qb = parent::buildQueryEntities($action, $request); + + return $this->filterQueryEntitiesByPerson($action, $qb, $request); + } + + /** + * @param \Chill\MainBundle\CRUD\Controller\string|string $action + */ + protected function createEntity($action, Request $request): object + { + $entity = parent::createEntity($action, $request); + + $person = $this->getPerson($request); + + $entity->setPerson($person); + + return $entity; + } + + /** + * Add a where clause to the buildQuery. + * + * @param \Chill\PersonBundle\CRUD\Controller\QueryBuilder $qb + * + * @return \Chill\PersonBundle\CRUD\Controller\QueryBuilder + */ + protected function filterQueryEntitiesByPerson(string $action, QueryBuilder $qb, Request $request): QueryBuilder + { + $qb->andWhere($qb->expr()->eq('e.person', ':person')); + $qb->setParameter('person', $this->getPerson($request)); + + return $qb; + } + + /** + * @param mixed $entity + * + * @throws Exception + */ + protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = []): array + { + $person = $this->getPerson($request); + + if (null === $person) { + throw new Exception('the `person_id` parameter is not set in the query. ' + . 'You should set it or override the current method to allow another ' + . 'behaviour: ' . __METHOD__); + } + + return parent::generateTemplateParameter( + $action, + $entity, + $request, + array_merge(['person' => $person], $defaultTemplateParameters) + ); + } + + /** + * Extract the person from the request. + * + * the person parameter will be `person_id` and must be * present in the query - * + * * If the parameter is not set, this method will return null. - * - * If the person id does not exists, the method will throw a + * + * If the person id does not exists, the method will throw a * Symfony\Component\HttpKernel\Exception\NotFoundHttpException - * - * @param Request $request + * * @throws Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the person with given id is not found */ protected function getPerson(Request $request): ?Person { - if (FALSE === $request->query->has('person_id')) { + if (false === $request->query->has('person_id')) { return null; } - + $person = $this->getDoctrine() ->getRepository(Person::class) - ->find($request->query->getInt('person_id')) - ; - - if (NULL === $person) { + ->find($request->query->getInt('person_id')); + + if (null === $person) { throw $this->createNotFoundException('the person with this id is not found'); } - + return $person; } - - /** - * @param \Chill\MainBundle\CRUD\Controller\string|string $action - * @param Request $request - * @return object - */ - protected function createEntity($action, Request $request): object - { - $entity = parent::createEntity($action, $request); - - $person = $this->getPerson($request); - - $entity->setPerson($person); - - return $entity; - } - + /** * @param string $action * @param mixed $entity - * @param Request $request - * @param array $defaultTemplateParameters - * @return array - * @throws \Exception - */ - protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = array()): array - { - $person = $this->getPerson($request); - - if (NULL === $person) { - throw new \Exception("the `person_id` parameter is not set in the query. " - . "You should set it or override the current method to allow another " - . "behaviour: ".__METHOD__); - } - - return parent::generateTemplateParameter( - $action, - $entity, - $request, - \array_merge([ 'person' => $person ], $defaultTemplateParameters) - ); - } - - /** - * @param string $action - * @param mixed $entity - * @param Request $request + * * @return string */ protected function getTemplateFor($action, $entity, Request $request) @@ -115,83 +128,59 @@ class EntityPersonCRUDController extends CRUDController if ($this->hasCustomTemplate($action, $entity, $request)) { return $this->getActionConfig($action)['template']; } - + switch ($action) { case 'new': return '@ChillPerson/CRUD/new.html.twig'; - case 'edit': + + case 'edit': return '@ChillPerson/CRUD/edit.html.twig'; + case 'view': return '@ChillPerson/CRUD/view.html.twig'; + case 'delete': return '@ChillPerson/CRUD/delete.html.twig'; + case 'index': return '@ChillPerson/CRUD/index.html.twig'; + default: return parent::getTemplateFor($action, $entity, $request); } } - + /** - * @param string $action * @param mixed $entity - * @param \Symfony\Component\Form\FormInterface $form - * @param Request $request + * * @return \Symfony\Component\HttpFoundation\RedirectResponse */ protected function onBeforeRedirectAfterSubmission(string $action, $entity, \Symfony\Component\Form\FormInterface $form, Request $request) { - $next = $request->request->get("submit", "save-and-close"); - + $next = $request->request->get('submit', 'save-and-close'); + switch ($next) { - case "save-and-close": - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index', [ - 'person_id' => $this->getPerson($request)->getId() + case 'save-and-close': + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index', [ + 'person_id' => $this->getPerson($request)->getId(), ]); - case "save-and-new": - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_new', [ - 'person_id' => $this->getPerson($request)->getId() + + case 'save-and-new': + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_new', [ + 'person_id' => $this->getPerson($request)->getId(), ]); - case "new": - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [ + + case 'new': + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', [ 'id' => $entity->getId(), - 'person_id' => $this->getPerson($request)->getId() + 'person_id' => $this->getPerson($request)->getId(), ]); + default: - return $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [ + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_view', [ 'id' => $entity->getId(), - 'person_id' => $this->getPerson($request)->getId() - ]); + 'person_id' => $this->getPerson($request)->getId(), + ]); } } - - /** - * Override the base method to add a filtering step to a person. - * - * @param string $action - * @param Request $request - * @return QueryBuilder - */ - protected function buildQueryEntities(string $action, Request $request) - { - $qb = parent::buildQueryEntities($action, $request); - - return $this->filterQueryEntitiesByPerson($action, $qb, $request); - } - - /** - * Add a where clause to the buildQuery - * - * @param string $action - * @param \Chill\PersonBundle\CRUD\Controller\QueryBuilder $qb - * @param Request $request - * @return \Chill\PersonBundle\CRUD\Controller\QueryBuilder - */ - protected function filterQueryEntitiesByPerson(string $action, QueryBuilder $qb, Request $request): QueryBuilder - { - $qb->andWhere($qb->expr()->eq('e.person', ':person')); - $qb->setParameter('person', $this->getPerson($request)); - - return $qb; - } } diff --git a/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php b/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php index 720de560c..8ff692168 100644 --- a/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php +++ b/src/Bundle/ChillPersonBundle/CRUD/Controller/OneToOneEntityPersonCRUDController.php @@ -1,89 +1,83 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\CRUD\Controller; use Chill\MainBundle\CRUD\Controller\CRUDController; -use Symfony\Component\HttpFoundation\Request; use Chill\PersonBundle\Entity\Person; +use LogicException; use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; /** - * Controller for entities attached as one-to-on to a person - * + * Controller for entities attached as one-to-on to a person. */ class OneToOneEntityPersonCRUDController extends CRUDController { - protected function getTemplateFor($action, $entity, Request $request) + protected function generateRedirectOnCreateRoute($action, Request $request, $entity) { - if (!empty($this->crudConfig[$action]['template'])) { - return $this->crudConfig[$action]['template']; - } - - switch ($action) { - case 'new': - return '@ChillPerson/CRUD/new.html.twig'; - case 'edit': - return '@ChillPerson/CRUD/edit.html.twig'; - case 'index': - return '@ChillPerson/CRUD/index.html.twig'; - default: - throw new \LogicException("the view for action $action is not " - . "defined. You should override ".__METHOD__." to add this " - . "action"); - } + throw new BadMethodCallException('not implemtented yet'); } - + protected function getEntity($action, $id, Request $request): ?object { $entity = parent::getEntity($action, $id, $request); - - if (NULL === $entity) { + + if (null === $entity) { $entity = $this->createEntity($action, $request); $person = $this->getDoctrine() ->getManager() ->getRepository(Person::class) ->find($id); - + $entity->setPerson($person); } - + return $entity; } - + + protected function getTemplateFor($action, $entity, Request $request) + { + if (!empty($this->crudConfig[$action]['template'])) { + return $this->crudConfig[$action]['template']; + } + + switch ($action) { + case 'new': + return '@ChillPerson/CRUD/new.html.twig'; + + case 'edit': + return '@ChillPerson/CRUD/edit.html.twig'; + + case 'index': + return '@ChillPerson/CRUD/index.html.twig'; + + default: + throw new LogicException("the view for action {$action} is not " + . 'defined. You should override ' . __METHOD__ . ' to add this ' + . 'action'); + } + } + + protected function onPostFetchEntity($action, Request $request, $entity): ?Response + { + if (false === $this->getDoctrine()->getManager()->contains($entity)) { + return new RedirectResponse($this->generateRedirectOnCreateRoute($action, $request, $entity)); + } + + return null; + } + protected function onPreFlush(string $action, $entity, FormInterface $form, Request $request) { $this->getDoctrine()->getManager()->persist($entity); } - - protected function onPostFetchEntity($action, Request $request, $entity): ?Response - { - if (FALSE === $this->getDoctrine()->getManager()->contains($entity)) { - return new RedirectResponse($this->generateRedirectOnCreateRoute($action, $request, $entity)); - } - - return null; - } - - protected function generateRedirectOnCreateRoute($action, Request $request, $entity) - { - throw new BadMethodCallException("not implemtented yet"); - } - } diff --git a/src/Bundle/ChillPersonBundle/ChillPersonBundle.php b/src/Bundle/ChillPersonBundle/ChillPersonBundle.php index 18bf8fb79..6041fa7ed 100644 --- a/src/Bundle/ChillPersonBundle/ChillPersonBundle.php +++ b/src/Bundle/ChillPersonBundle/ChillPersonBundle.php @@ -1,21 +1,28 @@ getExtension('chill_main') ->addWidgetFactory(new PersonListWidgetFactory()); - + $container->addCompilerPass(new AccompanyingPeriodTimelineCompilerPass()); } } diff --git a/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php b/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php index 4f2b2098a..b4aafa5e7 100644 --- a/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php +++ b/src/Bundle/ChillPersonBundle/Command/ChillPersonMoveCommand.php @@ -1,150 +1,142 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Command; +use Chill\PersonBundle\Actions\Remove\PersonMove; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Chill\PersonBundle\Actions\Remove\PersonMove; -use Doctrine\ORM\EntityManagerInterface; -use Chill\PersonBundle\Entity\Person; -use Symfony\Component\Console\Exception\RuntimeException; -use Psr\Log\LoggerInterface; + +use function ctype_digit; class ChillPersonMoveCommand extends ContainerAwareCommand { /** - * - * @var PersonMove - */ - protected $mover; - - /** - * - * @var EntityManagerInterface - */ - protected $em; - - /** - * * @var LoggerInterface */ protected $chillLogger; - + + /** + * @var EntityManagerInterface + */ + protected $em; + + /** + * @var PersonMove + */ + protected $mover; + public function __construct( - PersonMove $mover, + PersonMove $mover, EntityManagerInterface $em, LoggerInterface $chillLogger ) { parent::__construct('chill:person:move'); - + $this->mover = $mover; $this->em = $em; $this->chillLogger = $chillLogger; } - + + protected function buildLoggingContext(Person $from, Person $to, $deleteEntities, $sqls) + { + $ctxt = [ + 'from' => $from->getId(), + 'to' => $to->getId(), + ]; + + foreach ($deleteEntities as $key => $de) { + $ctxt['delete_entity_' . $key] = $de; + } + + foreach ($sqls as $key => $sql) { + $ctxt['sql_' . $key] = $sql; + } + + return $ctxt; + } + protected function configure() { $this ->setName('chill:person:move') ->setDescription('Move all the associated entities on a "from" person to a "to" person and remove the old person') - ->addOption('from', 'f', InputOption::VALUE_REQUIRED, "The person id to delete, all associated data will be moved before") - ->addOption('to', 't', InputOption::VALUE_REQUIRED, "The person id which will received data") - ->addOption('dump-sql', null, InputOption::VALUE_NONE, "dump sql to stdout") - ->addOption('force', null, InputOption::VALUE_NONE, "execute sql instead of dumping it") - ->addOption('delete-entity', null, InputOption::VALUE_REQUIRED|InputOption::VALUE_IS_ARRAY, "entity to delete", []) - ; - } - - protected function interact(InputInterface $input, OutputInterface $output) - { - if (FALSE === $input->hasOption('dump-sql') && FALSE === $input->hasOption('force')) { - $msg = "You must use \"--dump-sql\" or \"--force\""; - throw new RuntimeException($msg); - } - - foreach (["from", "to"] as $name) { - if (empty($input->getOption($name))) { - throw new RuntimeException("You must set a \"$name\" option"); - } - $id = $input->getOption($name); - if (\ctype_digit($id) === FALSE) { - throw new RuntimeException("The id in \"$name\" field does not contains " - . "only digits: $id"); - } - } + ->addOption('from', 'f', InputOption::VALUE_REQUIRED, 'The person id to delete, all associated data will be moved before') + ->addOption('to', 't', InputOption::VALUE_REQUIRED, 'The person id which will received data') + ->addOption('dump-sql', null, InputOption::VALUE_NONE, 'dump sql to stdout') + ->addOption('force', null, InputOption::VALUE_NONE, 'execute sql instead of dumping it') + ->addOption('delete-entity', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'entity to delete', []); } protected function execute(InputInterface $input, OutputInterface $output) { $repository = $this->em->getRepository(Person::class); $from = $repository->find($input->getOption('from')); - $to = $repository->find($input->getOption('to')); + $to = $repository->find($input->getOption('to')); $deleteEntities = $input->getOption('delete-entity'); - - if ($from === NULL) { - throw new RuntimeException(sprintf("Person \"from\" with id %d not found", $input->getOption('from'))); + + if (null === $from) { + throw new RuntimeException(sprintf('Person "from" with id %d not found', $input->getOption('from'))); } - if ($to === NULL) { - throw new RuntimeException(sprintf("Person \"to\" with id %d not found", $input->getOption('to'))); + + if (null === $to) { + throw new RuntimeException(sprintf('Person "to" with id %d not found', $input->getOption('to'))); } - + $sqls = $this->mover->getSQL($from, $to, $deleteEntities); - + if ($input->getOption('dump-sql')) { - foreach($sqls as $sql) { + foreach ($sqls as $sql) { $output->writeln($sql); } } else { $ctxt = $this->buildLoggingContext($from, $to, $deleteEntities, $sqls); - $this->chillLogger->notice("Trying to move a person from command line", $ctxt); + $this->chillLogger->notice('Trying to move a person from command line', $ctxt); $connection = $this->em->getConnection(); $connection->beginTransaction(); - foreach($sqls as $sql) { + + foreach ($sqls as $sql) { if ($output->isVerbose()) { $output->writeln($sql); } $connection->executeQuery($sql); } $connection->commit(); - - $this->chillLogger->notice("Move a person from command line succeeded", $ctxt); + + $this->chillLogger->notice('Move a person from command line succeeded', $ctxt); } } - - protected function buildLoggingContext(Person $from, Person $to, $deleteEntities, $sqls) - { - $ctxt = [ - 'from' => $from->getId(), - 'to' => $to->getId() - ]; - - foreach ($deleteEntities as $key => $de) { - $ctxt['delete_entity_'.$key] = $de; - } - foreach ($sqls as $key => $sql) { - $ctxt['sql_'.$key] = $sql; - } - - return $ctxt; - } + protected function interact(InputInterface $input, OutputInterface $output) + { + if (false === $input->hasOption('dump-sql') && false === $input->hasOption('force')) { + $msg = 'You must use "--dump-sql" or "--force"'; + + throw new RuntimeException($msg); + } + + foreach (['from', 'to'] as $name) { + if (empty($input->getOption($name))) { + throw new RuntimeException("You must set a \"{$name}\" option"); + } + $id = $input->getOption($name); + + if (ctype_digit($id) === false) { + throw new RuntimeException("The id in \"{$name}\" field does not contains " + . "only digits: {$id}"); + } + } + } } diff --git a/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php b/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php index d5e4c597c..ef2c5a1d0 100644 --- a/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php +++ b/src/Bundle/ChillPersonBundle/Command/ImportPeopleFromCSVCommand.php @@ -1,111 +1,115 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Command; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\PostalCode; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\Person; +use DateInterval; +use DateTime; use Doctrine\ORM\EntityManagerInterface; +use Exception; use Psr\Log\LoggerInterface; +use RuntimeException; use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Logger\ConsoleLogger; -use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\Console\Helper\Table; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Entity\PostalCode; -use Chill\MainBundle\Entity\Center; -use Chill\CustomFieldsBundle\Service\CustomFieldProvider; use Symfony\Component\Console\Question\ConfirmationQuestion; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Form\FormFactory; +use function array_key_exists; +use function file_get_contents; +use function json_decode; + /** - * Class ImportPeopleFromCSVCommand - * - * @package Chill\PersonBundle\Command - * @author Julien Fastré + * Class ImportPeopleFromCSVCommand. */ class ImportPeopleFromCSVCommand extends Command { - /** - * @var InputInterface - */ - protected $input; - - /** - * @var OutputInterface - */ - protected $output; - - /** - * @var \Psr\Log\LoggerInterface - */ - protected $logger; - - /** - * @var \Chill\MainBundle\Templating\TranslatableStringHelper - */ - protected $helper; - - /** - * @var \Doctrine\Persistence\ObjectManager - */ - protected $em; - - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - - /** - * the line currently read - * - * @var int - */ - protected $line; - + protected $cacheAnswersMapping = []; + /** * @var array where key are column names, and value the custom field slug */ - protected $customFieldMapping = array(); - + protected $customFieldMapping = []; + /** * @var CustomFieldProvider */ protected $customFieldProvider; - + + /** + * Different possible format to interpret a date. + * + * @var string + */ + protected static $defaultDateInterpreter = '%d/%m/%Y|%e/%m/%y|%d/%m/%Y|%e/%m/%Y'; + + /** + * @var \Doctrine\Persistence\ObjectManager + */ + protected $em; + + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * @var FormFactory + */ + protected $formFactory; + + /** + * @var \Chill\MainBundle\Templating\TranslatableStringHelper + */ + protected $helper; + + /** + * @var InputInterface + */ + protected $input; + + /** + * the line currently read. + * + * @var int + */ + protected $line; + + /** + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + /** * Contains an array of information searched in the file. - * + * * position 0: the information key (which will be used in this process) * position 1: the helper * position 2: the default value * * @var array */ - protected static $mapping = array( + protected static $mapping = [ ['firstname', 'The column header for firstname', 'firstname'], ['lastname', 'The column header for lastname', 'lastname'], ['birthdate', 'The column header for birthdate', 'birthdate'], @@ -119,30 +123,16 @@ class ImportPeopleFromCSVCommand extends Command ['street1', 'The column header for street 1', 'street1'], ['postalcode', 'The column header for postal code', 'postalcode'], ['locality', 'The column header for locality', 'locality'], - ['center', 'The column header for center', 'center'] - ); - + ['center', 'The column header for center', 'center'], + ]; + /** - * Different possible format to interpret a date - * - * @var string + * @var OutputInterface */ - protected static $defaultDateInterpreter = "%d/%m/%Y|%e/%m/%y|%d/%m/%Y|%e/%m/%Y"; - - /** - * @var FormFactory - */ - protected $formFactory; - + protected $output; + /** * ImportPeopleFromCSVCommand constructor. - * - * @param LoggerInterface $logger - * @param TranslatableStringHelper $helper - * @param EntityManagerInterface $em - * @param CustomFieldProvider $customFieldProvider - * @param EventDispatcherInterface $eventDispatcher - * @param FormFactory $formFactory */ public function __construct( LoggerInterface $logger, @@ -158,287 +148,315 @@ class ImportPeopleFromCSVCommand extends Command $this->customFieldProvider = $customFieldProvider; $this->eventDispatcher = $eventDispatcher; $this->formFactory = $formFactory; - + parent::__construct('chill:person:import'); } - - /** - * - */ - protected function configure() - { - $this - ->addArgument('csv_file', InputArgument::REQUIRED, "The CSV file to import") - ->setDescription("Import people from a csv file") - ->setHelp(<<addArgument('locale', InputArgument::REQUIRED, - "The locale to use in displaying translatable strings from entities") - ->addOption( - 'force-center', - null, - InputOption::VALUE_REQUIRED, - "The id of the center" - ) - ->addOption( - 'force', - null, - InputOption::VALUE_NONE, - "Persist people in the database (default is not to persist people)" - ) - ->addOption( - 'delimiter', - 'd', - InputOption::VALUE_OPTIONAL, - "The delimiter character of the csv file", - ",") - ->addOption( - 'enclosure', - null, - InputOption::VALUE_OPTIONAL, - "The enclosure character of the csv file", - '"' - ) - ->addOption( - 'escape', - null, - InputOption::VALUE_OPTIONAL, - "The escape character of the csv file", - "\\" - ) - ->addOption( - 'length', - null, - InputOption::VALUE_OPTIONAL, - "The length of line to read. 0 means unlimited.", - 0 - ) - ->addOption( - 'dump-choice-matching', - null, - InputOption::VALUE_REQUIRED, - "The path of the file to dump the matching between label in CSV and answers" - ) - ->addOption( - 'load-choice-matching', - null, - InputOption::VALUE_OPTIONAL, - "The path of the file to load the matching between label in CSV and answers" - ) - ; - - // mapping columns - foreach (self::$mapping as $m) { - $this->addOptionShortcut($m[0], $m[1], $m[2]); - } - - // other information - $this->addOptionShortcut('birthdate_format', 'Format preference for ' - . 'birthdate. See help for date formats preferences.', - self::$defaultDateInterpreter); - $this->addOptionShortcut('opening_date_format', 'Format preference for ' - . 'opening date. See help for date formats preferences.', - self::$defaultDateInterpreter); - $this->addOptionShortcut('closing_date_format', 'Format preference for ' - . 'closing date. See help for date formats preferences.', - self::$defaultDateInterpreter); - - // mapping column to custom fields - $this->addOption('custom-field', NULL, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - "Mapping a column to a custom fields key. Example: 1=cf_slug"); - $this->addOption('skip-interactive-field-mapping', null, InputOption::VALUE_NONE, - "Do not ask for interactive mapping"); - } - /** * This function is a shortcut to addOption. - * + * * @param string $name * @param string $description * @param string $default + * * @return ImportPeopleFromCSVCommand */ protected function addOptionShortcut($name, $description, $default) { $this->addOption($name, null, InputOption::VALUE_OPTIONAL, $description, $default); - + return $this; } - - /** - * @param InputInterface $input - * @param OutputInterface $output - */ - protected function interact(InputInterface $input, OutputInterface $output) - { - // preparing the basic - $this->input = $input; - $this->output = $output; - $this->logger = new ConsoleLogger($output); - - $csv = $this->openCSV(); - - // getting the first row - if (($row = fgetcsv( - $csv, - $input->getOption('length'), - $input->getOption('delimiter'), - $input->getOption('enclosure'), - $input->getOption('escape'))) !== false) { - - try { - $this->matchColumnToCustomField($row); - } finally { - $this->logger->debug('closing csv', array('method' => __METHOD__)); - fclose($csv); - } - } - - // load the matching between csv and label - $this->loadAnswerMatching(); - } - - /** - * @param $row - */ - protected function matchColumnToCustomField($row) - { - - $cfMappingsOptions = $this->input->getOption('custom-field'); - /* @var $em \Doctrine\Persistence\ObjectManager */ - $em = $this->em; - - foreach($cfMappingsOptions as $cfMappingStringOption) { - list($rowNumber, $cfSlug) = preg_split('|=|', $cfMappingStringOption); - - // check that the column exists, getting the column name - $column = $row[$rowNumber]; - - if (empty($column)) { - $message = "The column with row $rowNumber is empty."; - $this->logger->error($message); - throw new \RuntimeException($message); - } - - // check a custom field exists - try { - $customField = $em->createQuery("SELECT cf " - . "FROM ChillCustomFieldsBundle:CustomField cf " - . "JOIN cf.customFieldGroup g " - . "WHERE cf.slug = :slug " - . "AND g.entity = :entity") - ->setParameters(array( - 'slug' => $cfSlug, - 'entity' => Person::class - )) - ->getSingleResult(); - } catch (\Doctrine\ORM\NoResultException $e) { - $message = sprintf( - "The customfield with slug '%s' does not exists. It was associated with column number %d", - $cfSlug, - $rowNumber - ); - $this->logger->error($message); - throw new \RuntimeException($message); - } - // skip if custom field does not exists - if ($customField === NULL) { - $this->logger->error("The custom field with slug $cfSlug could not be found. " - . "Stopping this command."); - throw new \RuntimeException("The custom field with slug $cfSlug could not be found. " - . "Stopping this command."); - } - - $this->logger->notice(sprintf("Matched custom field %s (question : '%s') on column %d (displayed in the file as '%s')", - $customField->getSlug(), $this->helper->localize($customField->getName()), $rowNumber, $column)); - - $this->customFieldMapping[$rowNumber] = $customField; - } - } - - /** - * Load the mapping between answer in CSV and value in choices from a json file - */ - protected function loadAnswerMatching() - { - if ($this->input->hasOption('load-choice-matching')) { - $fs = new Filesystem(); - $filename = $this->input->getOption('load-choice-matching'); - if (!$fs->exists($filename)) { - $this->logger->warning("The file $filename is not found. Choice matching not loaded"); - } else { - $this->logger->debug("Loading $filename as choice matching"); - $this->cacheAnswersMapping = \json_decode(\file_get_contents($filename), true); + protected function configure() + { + $this + ->addArgument('csv_file', InputArgument::REQUIRED, 'The CSV file to import') + ->setDescription('Import people from a csv file') + ->setHelp( + <<<'EOF' + Import people from a csv file. The first row must contains the header column and will determines where the value will be matched. + + Date format: the possible date format may be separatedby an |. The possible format will be tryed from the first to the last. The format should be explained as http://php.net/manual/en/function.strftime.php + + php app/console chill:person:import /tmp/hepc.csv fr_FR.utf8 \ + --firstname="Prénom" --lastname="Nom" \ + --birthdate="D.N." --birthdate_format="%d/%m/%Y" \ + --opening_date_format="%B %Y|%Y" --closing_date="der.contact" \ + --closing_date_format="%Y" --custom-field="3=code" -vvv + EOF + ) + ->addArgument( + 'locale', + InputArgument::REQUIRED, + 'The locale to use in displaying translatable strings from entities' + ) + ->addOption( + 'force-center', + null, + InputOption::VALUE_REQUIRED, + 'The id of the center' + ) + ->addOption( + 'force', + null, + InputOption::VALUE_NONE, + 'Persist people in the database (default is not to persist people)' + ) + ->addOption( + 'delimiter', + 'd', + InputOption::VALUE_OPTIONAL, + 'The delimiter character of the csv file', + ',' + ) + ->addOption( + 'enclosure', + null, + InputOption::VALUE_OPTIONAL, + 'The enclosure character of the csv file', + '"' + ) + ->addOption( + 'escape', + null, + InputOption::VALUE_OPTIONAL, + 'The escape character of the csv file', + '\\' + ) + ->addOption( + 'length', + null, + InputOption::VALUE_OPTIONAL, + 'The length of line to read. 0 means unlimited.', + 0 + ) + ->addOption( + 'dump-choice-matching', + null, + InputOption::VALUE_REQUIRED, + 'The path of the file to dump the matching between label in CSV and answers' + ) + ->addOption( + 'load-choice-matching', + null, + InputOption::VALUE_OPTIONAL, + 'The path of the file to load the matching between label in CSV and answers' + ); + + // mapping columns + foreach (self::$mapping as $m) { + $this->addOptionShortcut($m[0], $m[1], $m[2]); + } + + // other information + $this->addOptionShortcut( + 'birthdate_format', + 'Format preference for ' + . 'birthdate. See help for date formats preferences.', + self::$defaultDateInterpreter + ); + $this->addOptionShortcut( + 'opening_date_format', + 'Format preference for ' + . 'opening date. See help for date formats preferences.', + self::$defaultDateInterpreter + ); + $this->addOptionShortcut( + 'closing_date_format', + 'Format preference for ' + . 'closing date. See help for date formats preferences.', + self::$defaultDateInterpreter + ); + + // mapping column to custom fields + $this->addOption( + 'custom-field', + null, + InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, + 'Mapping a column to a custom fields key. Example: 1=cf_slug' + ); + $this->addOption( + 'skip-interactive-field-mapping', + null, + InputOption::VALUE_NONE, + 'Do not ask for interactive mapping' + ); + } + + /** + * @param array $row + * @param array $headers the processed header : an array as prepared by self::processingHeaders + * + * @throws Exception + * + * @return Person + */ + protected function createPerson($row, $headers) + { + // trying to get the opening date + $openingDateString = trim($row[array_search('opening_date', $headers)]); + $openingDate = $this->processDate($openingDateString, $this->input->getOption('opening_date_format')); + + $person = $openingDate instanceof DateTime ? new Person($openingDate) : new Person(); + // add the center + $center = $this->getCenter($row, $headers); + + if (null === $center) { + throw new Exception('center not found'); + } + + $person->setCenter($center); + + foreach ($headers as $column => $info) { + $value = trim($row[$column]); + + switch ($info) { + case 'firstname': + $person->setFirstName($value); + + break; + + case 'lastname': + $person->setLastName($value); + + break; + + case 'birthdate': + $this->processBirthdate($person, $value); + + break; + + case 'gender': + $person->setGender($value); + + break; + + case 'opening_date': + // we have processed this when creating the person object, skipping; + break; + + case 'closing_date': + $this->processClosingDate($person, $value); + + break; + + case 'memo': + $person->setMemo($value); + + break; + + case 'email': + $person->setEmail($value); + + break; + + case 'phonenumber': + $person->setPhonenumber($value); + + break; + + case 'mobilenumber': + $person->setMobilenumber($value); + + break; + // we just keep the column number for those data + case 'postalcode': + $postalCodeValue = $value; + + break; + + case 'street1': + $street1Value = $value; + + break; + + case 'locality': + $localityValue = $value; + + break; } } + + // handle address + if (\in_array('postalcode', $headers)) { + if (!empty($postalCodeValue)) { + $address = new Address(); + $postalCode = $this->guessPostalCode($postalCodeValue, $localityValue ?? ''); + + if (null === $postalCode) { + throw new Exception('The locality is not found'); + } + + $address->setPostcode($postalCode); + + if (\in_array('street1', $headers)) { + $address->setStreetAddress1($street1Value); + } + $address->setValidFrom(new DateTime('today')); + + $person->addAddress($address); + } + } + + return $person; } - - /** - * - */ + protected function dumpAnswerMatching() { if ($this->input->hasOption('dump-choice-matching') && !empty($this->input->getOption('dump-choice-matching'))) { - $this->logger->debug("Dump the matching between answer and choices"); + $this->logger->debug('Dump the matching between answer and choices'); $str = json_encode($this->cacheAnswersMapping, JSON_PRETTY_PRINT); - + $fs = new Filesystem(); $filename = $this->input->getOption('dump-choice-matching'); - + $fs->dumpFile($filename, $str); } } - + /** - * @param InputInterface $input - * @param OutputInterface $output - * @return int|null|void - * @throws \Exception + * @throws Exception + * + * @return int|void|null */ protected function execute(InputInterface $input, OutputInterface $output) { $this->input = $input; $this->output = $output; - - $this->logger->debug("Setting locale to ".$input->getArgument('locale')); + + $this->logger->debug('Setting locale to ' . $input->getArgument('locale')); setlocale(LC_TIME, $input->getArgument('locale')); - + // opening csv as resource $csv = $this->openCSV(); - + $num = 0; $line = $this->line = 1; - + try { - while (($row = fgetcsv( - $csv, - $input->getOption('length'), - $input->getOption('delimiter'), - $input->getOption('enclosure'), - $input->getOption('escape'))) !== false) { - $this->logger->debug("Processing line ".$this->line); - if ($line === 1 ) { + while ( + false !== ($row = fgetcsv( + $csv, + $input->getOption('length'), + $input->getOption('delimiter'), + $input->getOption('enclosure'), + $input->getOption('escape') + )) + ) { + $this->logger->debug('Processing line ' . $this->line); + + if (1 === $line) { $this->logger->debug('Processing line 1, headers'); $rawHeaders = $row; $headers = $this->processingHeaders($row); } else { $person = $this->createPerson($row, $headers); - + if (count($this->customFieldMapping) > 0) { $this->processingCustomFields($person, $row); } - + $event = new Event(); $event->person = $person; $event->rawHeaders = $rawHeaders; @@ -449,492 +467,384 @@ EOF $event->input = $this->input; $event->output = $this->output; $event->helperSet = $this->getHelperSet(); - + $this->eventDispatcher->dispatch('chill_person.person_import', $event); - - if ($this->input->getOption('force') === TRUE - && $event->skipPerson === false) { + + if ( + $this->input->getOption('force') === true + && false === $event->skipPerson + ) { $this->em->persist($person); } - - $num ++; + + ++$num; } - $line ++; - $this->line++; + ++$line; + ++$this->line; } - + if ($this->input->getOption('force') === true) { $this->logger->debug('persisting entitites'); $this->em->flush(); } } finally { - $this->logger->debug('closing csv', array('method' => __METHOD__)); + $this->logger->debug('closing csv', ['method' => __METHOD__]); fclose($csv); // dump the matching between answer and choices $this->dumpAnswerMatching(); } } - - /** - * - * @return resource - * @throws \RuntimeException - */ - protected function openCSV() - { - $fs = new Filesystem(); - $filename = $this->input->getArgument('csv_file'); - - if (!$fs->exists($filename)) { - throw new \RuntimeException("The file does not exists or you do not " - . "have the right to read it."); - } - - $resource = fopen($filename, 'r'); - - if ($resource == FALSE) { - throw new \RuntimeException("The file '$filename' could not be opened."); - } - - return $resource; - } - - /** - * - * @param type $firstRow - * @return array where keys are column number, and value is information mapped - */ - protected function processingHeaders($firstRow) - { - $availableOptions = array_map(function($m) { return $m[0]; }, self::$mapping); - $matchedColumnHeaders = array(); - $headers = array(); - - foreach($availableOptions as $option) { - $matchedColumnHeaders[$option] = $this->input->getOption($option); - } - - foreach($firstRow as $key => $content) { - $content = trim($content); - if (in_array($content, $matchedColumnHeaders)) { - $information = array_search($content, $matchedColumnHeaders); - $headers[$key] = $information; - $this->logger->notice("Matched $information on column $key (displayed in the file as '$content')"); - } else { - $this->logger->notice("Column with content '$content' is ignored"); - } - } - - return $headers; - } - - /** - * - * @param array $row - * @param array $headers the processed header : an array as prepared by self::processingHeaders - * @return Person - * @throws \Exception - */ - protected function createPerson($row, $headers) - { - // trying to get the opening date - $openingDateString = trim($row[array_search('opening_date', $headers)]); - $openingDate = $this->processDate($openingDateString, $this->input->getOption('opening_date_format')); - - $person = $openingDate instanceof \DateTime ? new Person($openingDate) : new Person(); - // add the center - $center = $this->getCenter($row, $headers); - - if ($center === null) { - throw new \Exception("center not found"); - } - - $person->setCenter($center); - - foreach($headers as $column => $info) { - - $value = trim($row[$column]); - - switch($info) { - case 'firstname': - $person->setFirstName($value); - break; - case 'lastname': - $person->setLastName($value); - break; - case 'birthdate': - $this->processBirthdate($person, $value); - break; - case 'gender': - $person->setGender($value); - break; - case 'opening_date': - // we have processed this when creating the person object, skipping; - break; - case 'closing_date': - $this->processClosingDate($person, $value); - break; - case 'memo': - $person->setMemo($value); - break; - case 'email': - $person->setEmail($value); - break; - case 'phonenumber': - $person->setPhonenumber($value); - break; - case 'mobilenumber': - $person->setMobilenumber($value); - break; - - // we just keep the column number for those data - case 'postalcode': - $postalCodeValue = $value; - break; - case 'street1': - $street1Value = $value; - break; - case 'locality': - $localityValue = $value; - break; - } - } - - // handle address - if (\in_array('postalcode', $headers)) { - - if (! empty($postalCodeValue)) { - - $address = new Address(); - $postalCode = $this->guessPostalCode($postalCodeValue, $localityValue ?? ''); - - if ($postalCode === null) { - throw new \Exception("The locality is not found"); - } - - $address->setPostcode($postalCode); - - if (\in_array('street1', $headers)) { - $address->setStreetAddress1($street1Value); - } - $address->setValidFrom(new \DateTime('today')); - - $person->addAddress($address); - } - } - - return $person; - } - + /** * @param $row * @param $headers - * @return Center|mixed|null|object + * + * @return Center|mixed|object|null */ protected function getCenter($row, $headers) { if ($this->input->hasOption('force-center') && !empty($this->input->getOption('force-center'))) { return $this->em->getRepository('ChillMainBundle:Center') ->find($this->input->getOption('force-center')); - } else { - $columnCenter = \array_search('center', $headers); - $centerName = \trim($row[$columnCenter]); - - try { - return $this->em->createQuery('SELECT c FROM ChillMainBundle:Center c ' + } + $columnCenter = \array_search('center', $headers); + $centerName = \trim($row[$columnCenter]); + + try { + return $this->em->createQuery('SELECT c FROM ChillMainBundle:Center c ' . 'WHERE c.name = :center_name') - ->setParameter('center_name', $centerName) - ->getSingleResult() - ; - } catch (\Doctrine\ORM\NonUniqueResultException $e) { - return $this->guessCenter($centerName); - } catch (\Doctrine\ORM\NoResultException $e) { - return $this->guessCenter($centerName); - } + ->setParameter('center_name', $centerName) + ->getSingleResult(); + } catch (\Doctrine\ORM\NonUniqueResultException $e) { + return $this->guessCenter($centerName); + } catch (\Doctrine\ORM\NoResultException $e) { + return $this->guessCenter($centerName); } } - + /** * @param $centerName - * @return Center|mixed|null|object + * + * @return Center|mixed|object|null */ protected function guessCenter($centerName) { - if (!\array_key_exists('_center_picked', $this->cacheAnswersMapping)) { + if (!array_key_exists('_center_picked', $this->cacheAnswersMapping)) { $this->cacheAnswersMapping['_center_picked'] = []; } - - if (\array_key_exists($centerName, $this->cacheAnswersMapping['_center_picked'])) { + + if (array_key_exists($centerName, $this->cacheAnswersMapping['_center_picked'])) { $id = $this->cacheAnswersMapping['_center_picked'][$centerName]; - + return $this->em->getRepository(Center::class) ->find($id); } - - $centers = $this->em->createQuery("SELECT c FROM ChillMainBundle:Center c " - . "ORDER BY SIMILARITY(c.name, :center_name) DESC") + + $centers = $this->em->createQuery('SELECT c FROM ChillMainBundle:Center c ' + . 'ORDER BY SIMILARITY(c.name, :center_name) DESC') ->setParameter('center_name', $centerName) ->setMaxResults(10) - ->getResult() - ; - + ->getResult(); + if (count($centers) > 1) { if (\strtolower($centers[0]->getName()) === \strtolower($centerName)) { return $centers[0]; } } - + $centersByName = []; - $names = \array_map(function(Center $c) use (&$centersByName) { + $names = \array_map(function (Center $c) use (&$centersByName) { $n = $c->getName(); $centersByName[$n] = $c; + return $n; - }, $centers); - $names[] = "none of them"; - + $names[] = 'none of them'; + $helper = $this->getHelper('question'); - $question = new ChoiceQuestion(sprintf("Which center match the name \"%s\" ? (default to \"%s\")", $centerName, $names[0]), + $question = new ChoiceQuestion( + sprintf('Which center match the name "%s" ? (default to "%s")', $centerName, $names[0]), $names, - 0); - + 0 + ); + $answer = $helper->ask($this->input, $this->output, $question); - - if ($answer === 'none of them') { - $questionCreate = new ConfirmationQuestion("Would you like to create it ?", false); + + if ('none of them' === $answer) { + $questionCreate = new ConfirmationQuestion('Would you like to create it ?', false); $create = $helper->ask($this->input, $this->output, $questionCreate); - + if ($create) { $center = (new Center()) - ->setName($centerName) - ; - - if ($this->input->getOption('force') === TRUE) { + ->setName($centerName); + + if ($this->input->getOption('force') === true) { $this->em->persist($center); $this->em->flush(); } - + return $center; } } - + $center = $centersByName[$answer]; - + $this->cacheAnswersMapping['_center_picked'][$centerName] = $center->getId(); - + return $center; } - + /** * @param $postalCode * @param $locality + * * @return mixed|null */ protected function guessPostalCode($postalCode, $locality) { - if (!\array_key_exists('_postal_code_picked', $this->cacheAnswersMapping)) { + if (!array_key_exists('_postal_code_picked', $this->cacheAnswersMapping)) { $this->cacheAnswersMapping['_postal_code_picked'] = []; } - - if (\array_key_exists($postalCode, $this->cacheAnswersMapping['_postal_code_picked'])) { - if (\array_key_exists($locality, $this->cacheAnswersMapping['_postal_code_picked'][$postalCode])) { + + if (array_key_exists($postalCode, $this->cacheAnswersMapping['_postal_code_picked'])) { + if (array_key_exists($locality, $this->cacheAnswersMapping['_postal_code_picked'][$postalCode])) { $id = $this->cacheAnswersMapping['_postal_code_picked'][$postalCode][$locality]; - + return $this->em->getRepository(PostalCode::class)->find($id); } } - - $postalCodes = $this->em->createQuery("SELECT pc FROM ".PostalCode::class." pc " - . "WHERE pc.code = :postal_code " - . "ORDER BY SIMILARITY(pc.name, :locality) DESC " - ) + + $postalCodes = $this->em->createQuery( + 'SELECT pc FROM ' . PostalCode::class . ' pc ' + . 'WHERE pc.code = :postal_code ' + . 'ORDER BY SIMILARITY(pc.name, :locality) DESC ' + ) ->setMaxResults(10) ->setParameter('postal_code', $postalCode) ->setParameter('locality', $locality) - ->getResult() - ; - + ->getResult(); + if (count($postalCodes) >= 1) { - if ($postalCodes[0]->getCode() === $postalCode - && $postalCodes[0]->getName() === $locality) { + if ( + $postalCodes[0]->getCode() === $postalCode + && $postalCodes[0]->getName() === $locality + ) { return $postalCodes[0]; } } - + if (count($postalCodes) === 0) { return null; } - + $postalCodeByName = []; - $names = \array_map(function(PostalCode $pc) use (&$postalCodeByName) { + $names = \array_map(function (PostalCode $pc) use (&$postalCodeByName) { $n = $pc->getName(); $postalCodeByName[$n] = $pc; - + return $n; }, $postalCodes); $names[] = 'none of them'; - + $helper = $this->getHelper('question'); - $question = new ChoiceQuestion(sprintf("Which postal code match the " - . "name \"%s\" with postal code \"%s\" ? (default to \"%s\")", - $locality, $postalCode, $names[0]), + $question = new ChoiceQuestion( + sprintf( + 'Which postal code match the ' + . 'name "%s" with postal code "%s" ? (default to "%s")', + $locality, + $postalCode, + $names[0] + ), $names, - 0); - + 0 + ); + $answer = $helper->ask($this->input, $this->output, $question); - - if ($answer === 'none of them') { + + if ('none of them' === $answer) { return null; } - + $pc = $postalCodeByName[$answer]; - - $this->cacheAnswersMapping['_postal_code_picked'][$postalCode][$locality] = + + $this->cacheAnswersMapping['_postal_code_picked'][$postalCode][$locality] = $pc->getId(); - + return $pc; } - + + protected function interact(InputInterface $input, OutputInterface $output) + { + // preparing the basic + $this->input = $input; + $this->output = $output; + $this->logger = new ConsoleLogger($output); + + $csv = $this->openCSV(); + + // getting the first row + if ( + false !== ($row = fgetcsv( + $csv, + $input->getOption('length'), + $input->getOption('delimiter'), + $input->getOption('enclosure'), + $input->getOption('escape') + )) + ) { + try { + $this->matchColumnToCustomField($row); + } finally { + $this->logger->debug('closing csv', ['method' => __METHOD__]); + fclose($csv); + } + } + + // load the matching between csv and label + $this->loadAnswerMatching(); + } + + /** + * Load the mapping between answer in CSV and value in choices from a json file. + */ + protected function loadAnswerMatching() + { + if ($this->input->hasOption('load-choice-matching')) { + $fs = new Filesystem(); + $filename = $this->input->getOption('load-choice-matching'); + + if (!$fs->exists($filename)) { + $this->logger->warning("The file {$filename} is not found. Choice matching not loaded"); + } else { + $this->logger->debug("Loading {$filename} as choice matching"); + $this->cacheAnswersMapping = json_decode(file_get_contents($filename), true); + } + } + } + + /** + * @param $row + */ + protected function matchColumnToCustomField($row) + { + $cfMappingsOptions = $this->input->getOption('custom-field'); + /* @var $em \Doctrine\Persistence\ObjectManager */ + $em = $this->em; + + foreach ($cfMappingsOptions as $cfMappingStringOption) { + [$rowNumber, $cfSlug] = preg_split('|=|', $cfMappingStringOption); + + // check that the column exists, getting the column name + $column = $row[$rowNumber]; + + if (empty($column)) { + $message = "The column with row {$rowNumber} is empty."; + $this->logger->error($message); + + throw new RuntimeException($message); + } + + // check a custom field exists + try { + $customField = $em->createQuery('SELECT cf ' + . 'FROM ChillCustomFieldsBundle:CustomField cf ' + . 'JOIN cf.customFieldGroup g ' + . 'WHERE cf.slug = :slug ' + . 'AND g.entity = :entity') + ->setParameters([ + 'slug' => $cfSlug, + 'entity' => Person::class, + ]) + ->getSingleResult(); + } catch (\Doctrine\ORM\NoResultException $e) { + $message = sprintf( + "The customfield with slug '%s' does not exists. It was associated with column number %d", + $cfSlug, + $rowNumber + ); + $this->logger->error($message); + + throw new RuntimeException($message); + } + // skip if custom field does not exists + if (null === $customField) { + $this->logger->error("The custom field with slug {$cfSlug} could not be found. " + . 'Stopping this command.'); + + throw new RuntimeException("The custom field with slug {$cfSlug} could not be found. " + . 'Stopping this command.'); + } + + $this->logger->notice(sprintf( + "Matched custom field %s (question : '%s') on column %d (displayed in the file as '%s')", + $customField->getSlug(), + $this->helper->localize($customField->getName()), + $rowNumber, + $column + )); + + $this->customFieldMapping[$rowNumber] = $customField; + } + } + + /** + * @throws RuntimeException + * + * @return resource + */ + protected function openCSV() + { + $fs = new Filesystem(); + $filename = $this->input->getArgument('csv_file'); + + if (!$fs->exists($filename)) { + throw new RuntimeException('The file does not exists or you do not ' + . 'have the right to read it.'); + } + + $resource = fopen($filename, 'r'); + + if (false == $resource) { + throw new RuntimeException("The file '{$filename}' could not be opened."); + } + + return $resource; + } + /** - * @param Person $person * @param $value - * @throws \Exception + * + * @throws Exception */ protected function processBirthdate(Person $person, $value) { - if (empty($value)) { return; } - - $date = $this->processDate($value, $this->input->getOption('birthdate_format')); - - if ($date instanceof \DateTime) { - // we correct birthdate if the date is in the future - // the most common error is to set date 100 years to late (ex. 2063 instead of 1963) - if ($date > new \DateTime('yesterday')) { - $date = $date->sub(new \DateInterval('P100Y')); - } - - $person->setBirthdate($date); - + if (empty($value)) { return; } - - // if we arrive here, we could not process the date - $this->logger->warning(sprintf( - "Line %d : the birthdate could not be interpreted. Was %s.", - $this->line, - $value)); - - } - - /** - * @param Person $person - * @param $value - * @throws \Exception - */ - protected function processClosingDate(Person $person, $value) - { - if (empty($value)) { return; } - - // we skip if the opening date is now (or after yesterday) - /* @var $period \Chill\PersonBundle\Entity\AccompanyingPeriod */ - $period = $person->getCurrentAccompanyingPeriod(); - - if ($period->getOpeningDate() > new \DateTime('yesterday')) { - $this->logger->debug(sprintf("skipping a closing date because opening date is after yesterday (%s)", - $period->getOpeningDate()->format('Y-m-d'))); - return; - } - - - $date = $this->processDate($value, $this->input->getOption('closing_date_format')); - - if ($date instanceof \DateTime) { - // we correct birthdate if the date is in the future - // the most common error is to set date 100 years to late (ex. 2063 instead of 1963) - if ($date > new \DateTime('yesterday')) { - $date = $date->sub(new \DateInterval('P100Y')); - } - - $period->setClosingDate($date); - $person->close(); - return; - } - - // if we arrive here, we could not process the date - $this->logger->warning(sprintf( - "Line %d : the closing date could not be interpreted. Was %s.", - $this->line, - $value)); - } - - /** - * @param Person $person - * @param $row - * @throws \Exception - */ - protected function processingCustomFields(Person $person, $row) - { - - /* @var $cfProvider \Chill\CustomFieldsBundle\Service\CustomFieldProvider */ - $cfProvider = $this->customFieldProvider; - $cfData = array(); - - /* @var $$customField \Chill\CustomFieldsBundle\Entity\CustomField */ - foreach($this->customFieldMapping as $rowNumber => $customField) { - $builder = $this->formFactory->createBuilder(); - $cfProvider->getCustomFieldByType($customField->getType()) - ->buildForm($builder, $customField); - $form = $builder->getForm(); - - // get the type of the form - $type = get_class($form->get($customField->getSlug()) - ->getConfig()->getType()->getInnerType()); - $this->logger->debug(sprintf("Processing a form of type %s", - $type)); - switch ($type) { - case \Symfony\Component\Form\Extension\Core\Type\TextType::class: - $cfData[$customField->getSlug()] = - $this->processTextType($row[$rowNumber], $form, $customField); - break; - case \Symfony\Component\Form\Extension\Core\Type\ChoiceType::class: - case \Chill\MainBundle\Form\Type\Select2ChoiceType::class: - $cfData[$customField->getSlug()] = - $this->processChoiceType($row[$rowNumber], $form, $customField); + $date = $this->processDate($value, $this->input->getOption('birthdate_format')); + + if ($date instanceof DateTime) { + // we correct birthdate if the date is in the future + // the most common error is to set date 100 years to late (ex. 2063 instead of 1963) + if ($date > new DateTime('yesterday')) { + $date = $date->sub(new DateInterval('P100Y')); } - + + $person->setBirthdate($date); + + return; } - - $person->setCFData($cfData); + + // if we arrive here, we could not process the date + $this->logger->warning(sprintf( + 'Line %d : the birthdate could not be interpreted. Was %s.', + $this->line, + $value + )); } - - /** - * Process a text type on a custom field - * - * @param type $value - * @param \Symfony\Component\Form\FormInterface $form - * @return type - */ - protected function processTextType( - $value, - \Symfony\Component\Form\FormInterface $form, - \Chill\CustomFieldsBundle\Entity\CustomField $cf - ) - { - $form->submit(array($cf->getSlug() => $value)); - - $value = $form->getData()[$cf->getSlug()]; - - $this->logger->debug(sprintf("Found value : %s for custom field with question " - . "'%s'", $value, $this->helper->localize($cf->getName()))); - - return $value; - } - - protected $cacheAnswersMapping = array(); - - + /** * Process a custom field choice. * @@ -942,189 +852,347 @@ EOF * choices. If the texts exists, then this is picked. Else, ask the user. * * @param string $value - * @param \Symfony\Component\Form\FormInterface $form - * @param \Chill\CustomFieldsBundle\Entity\CustomField $cf + * + * @throws Exception + * * @return string - * @throws \Exception */ protected function processChoiceType( - $value, - \Symfony\Component\Form\FormInterface $form, - \Chill\CustomFieldsBundle\Entity\CustomField $cf - ) - { + $value, + \Symfony\Component\Form\FormInterface $form, + \Chill\CustomFieldsBundle\Entity\CustomField $cf + ) { // getting the possible answer and their value : $view = $form->get($cf->getSlug())->createView(); $answers = $this->collectChoicesAnswers($view->vars['choices']); - + // if we do not have any answer on the question, throw an error. if (count($answers) === 0) { $message = sprintf( - "The question '%s' with slug '%s' does not count any answer.", - $this->helper->localize($cf->getName()), - $cf->getSlug() - ); - - $this->logger->error($message, array( + "The question '%s' with slug '%s' does not count any answer.", + $this->helper->localize($cf->getName()), + $cf->getSlug() + ); + + $this->logger->error($message, [ 'method' => __METHOD__, 'slug' => $cf->getSlug(), - 'question' => $this->helper->localize($cf->getName()) - )); - - throw new \RuntimeException($message); + 'question' => $this->helper->localize($cf->getName()), + ]); + + throw new RuntimeException($message); } - - if ($view->vars['required'] === false) { + + if (false === $view->vars['required']) { $answers[null] = '** no answer'; } - + // the answer does not exists in cache. Try to find it, or asks the user if (!isset($this->cacheAnswersMapping[$cf->getSlug()][$value])) { - // try to find the answer (with array_keys and a search value $values = array_keys( - array_map(function($label) { return trim(strtolower($label)); }, $answers), - trim(strtolower($value)), - true - ); - + array_map(function ($label) { + return trim(strtolower($label)); + }, $answers), + trim(strtolower($value)), + true + ); + if (count($values) === 1) { // we could guess an answer ! - $this->logger->info("This question accept multiple answers"); - $this->cacheAnswersMapping[$cf->getSlug()][$value] = - $view->vars['multiple'] == false ? $values[0] : array($values[0]); - $this->logger->info(sprintf("Guessed that value '%s' match with key '%s' " - . "because the CSV and the label are equals.", - $value, $values[0])); + $this->logger->info('This question accept multiple answers'); + $this->cacheAnswersMapping[$cf->getSlug()][$value] = + false == $view->vars['multiple'] ? $values[0] : [$values[0]]; + $this->logger->info(sprintf( + "Guessed that value '%s' match with key '%s' " + . 'because the CSV and the label are equals.', + $value, + $values[0] + )); } else { // we could nog guess an answer. Asking the user. - $this->output->writeln("I do not know the answer to this question : "); + $this->output->writeln('I do not know the answer to this question : '); $this->output->writeln($this->helper->localize($cf->getName())); // printing the possible answers /* @var $table \Symfony\Component\Console\Helper\Table */ $table = new Table($this->output); - $table->setHeaders(array('#', 'label', 'value')); + $table->setHeaders(['#', 'label', 'value']); $i = 0; - foreach($answers as $key => $answer) { - $table->addRow(array( - $i, $answer, $key - )); + foreach ($answers as $key => $answer) { + $table->addRow([ + $i, $answer, $key, + ]); $matchingTableRowAnswer[$i] = $key; - $i++; + ++$i; } $table->render($this->output); $question = new ChoiceQuestion( - sprintf('Please pick your choice for the value "%s"', $value), - array_keys($matchingTableRowAnswer) - ); - $question->setErrorMessage("This choice is not possible"); - + sprintf('Please pick your choice for the value "%s"', $value), + array_keys($matchingTableRowAnswer) + ); + $question->setErrorMessage('This choice is not possible'); + if ($view->vars['multiple']) { - $this->logger->debug("this question is multiple"); + $this->logger->debug('this question is multiple'); $question->setMultiselect(true); } - + $selected = $this->getHelper('question')->ask($this->input, $this->output, $question); - $this->output->writeln(sprintf('You have selected "%s"', - is_array($answers[$matchingTableRowAnswer[$selected]]) ? + $this->output->writeln( + sprintf( + 'You have selected "%s"', + is_array($answers[$matchingTableRowAnswer[$selected]]) ? implode(',', $answers[$matchingTableRowAnswer[$selected]]) : - $answers[$matchingTableRowAnswer[$selected]]) - ); - + $answers[$matchingTableRowAnswer[$selected]] + ) + ); + // recording value in cache $this->cacheAnswersMapping[$cf->getSlug()][$value] = $matchingTableRowAnswer[$selected]; - $this->logger->debug(sprintf("Setting the value '%s' in cache for customfield '%s' and answer '%s'", - is_array($this->cacheAnswersMapping[$cf->getSlug()][$value]) ? + $this->logger->debug(sprintf( + "Setting the value '%s' in cache for customfield '%s' and answer '%s'", + is_array($this->cacheAnswersMapping[$cf->getSlug()][$value]) ? implode(', ', $this->cacheAnswersMapping[$cf->getSlug()][$value]) : $this->cacheAnswersMapping[$cf->getSlug()][$value], - $cf->getSlug(), - $value)); + $cf->getSlug(), + $value + )); } } - - $form->submit(array($cf->getSlug() => $this->cacheAnswersMapping[$cf->getSlug()][$value])); + + $form->submit([$cf->getSlug() => $this->cacheAnswersMapping[$cf->getSlug()][$value]]); $value = $form->getData()[$cf->getSlug()]; - - $this->logger->debug(sprintf( - "Found value : %s for custom field with question '%s'", - is_array($value) ? implode(',', $value) : $value, - $this->helper->localize($cf->getName())) - ); - + + $this->logger->debug( + sprintf( + "Found value : %s for custom field with question '%s'", + is_array($value) ? implode(',', $value) : $value, + $this->helper->localize($cf->getName()) + ) + ); + return $value; } - + + /** + * @param $value + * + * @throws Exception + */ + protected function processClosingDate(Person $person, $value) + { + if (empty($value)) { + return; + } + + // we skip if the opening date is now (or after yesterday) + /* @var $period \Chill\PersonBundle\Entity\AccompanyingPeriod */ + $period = $person->getCurrentAccompanyingPeriod(); + + if ($period->getOpeningDate() > new DateTime('yesterday')) { + $this->logger->debug(sprintf( + 'skipping a closing date because opening date is after yesterday (%s)', + $period->getOpeningDate()->format('Y-m-d') + )); + + return; + } + + $date = $this->processDate($value, $this->input->getOption('closing_date_format')); + + if ($date instanceof DateTime) { + // we correct birthdate if the date is in the future + // the most common error is to set date 100 years to late (ex. 2063 instead of 1963) + if ($date > new DateTime('yesterday')) { + $date = $date->sub(new DateInterval('P100Y')); + } + + $period->setClosingDate($date); + $person->close(); + + return; + } + + // if we arrive here, we could not process the date + $this->logger->warning(sprintf( + 'Line %d : the closing date could not be interpreted. Was %s.', + $this->line, + $value + )); + } + + /** + * @param $value + * @param $formats + * + * @return bool|DateTime + */ + protected function processDate($value, $formats) + { + $possibleFormats = explode('|', $formats); + + foreach ($possibleFormats as $format) { + $this->logger->debug("Trying format {$format}", [__METHOD__]); + $dateR = strptime($value, $format); + + if (is_array($dateR) && '' === $dateR['unparsed']) { + $string = sprintf( + '%04d-%02d-%02d %02d:%02d:%02d', + ($dateR['tm_year'] + 1900), + ($dateR['tm_mon'] + 1), + ($dateR['tm_mday']), + ($dateR['tm_hour']), + ($dateR['tm_min']), + ($dateR['tm_sec']) + ); + $date = DateTime::createFromFormat('Y-m-d H:i:s', $string); + $this->logger->debug(sprintf('Interpreting %s as date %s', $value, $date->format('Y-m-d H:i:s'))); + + return $date; + } + } + + // if we arrive here, we could not process the date + $this->logger->debug(sprintf( + 'Line %d : a date could not be interpreted. Was %s.', + $this->line, + $value + )); + + return false; + } + + /** + * @param $row + * + * @throws Exception + */ + protected function processingCustomFields(Person $person, $row) + { + /* @var $cfProvider \Chill\CustomFieldsBundle\Service\CustomFieldProvider */ + $cfProvider = $this->customFieldProvider; + $cfData = []; + + /* @var $$customField \Chill\CustomFieldsBundle\Entity\CustomField */ + foreach ($this->customFieldMapping as $rowNumber => $customField) { + $builder = $this->formFactory->createBuilder(); + $cfProvider->getCustomFieldByType($customField->getType()) + ->buildForm($builder, $customField); + $form = $builder->getForm(); + + // get the type of the form + $type = get_class($form->get($customField->getSlug()) + ->getConfig()->getType()->getInnerType()); + $this->logger->debug(sprintf( + 'Processing a form of type %s', + $type + )); + + switch ($type) { + case \Symfony\Component\Form\Extension\Core\Type\TextType::class: + $cfData[$customField->getSlug()] = + $this->processTextType($row[$rowNumber], $form, $customField); + + break; + + case \Symfony\Component\Form\Extension\Core\Type\ChoiceType::class: + case \Chill\MainBundle\Form\Type\Select2ChoiceType::class: + $cfData[$customField->getSlug()] = + $this->processChoiceType($row[$rowNumber], $form, $customField); + } + } + + $person->setCFData($cfData); + } + + /** + * @param type $firstRow + * + * @return array where keys are column number, and value is information mapped + */ + protected function processingHeaders($firstRow) + { + $availableOptions = array_map(function ($m) { + return $m[0]; + }, self::$mapping); + $matchedColumnHeaders = []; + $headers = []; + + foreach ($availableOptions as $option) { + $matchedColumnHeaders[$option] = $this->input->getOption($option); + } + + foreach ($firstRow as $key => $content) { + $content = trim($content); + + if (in_array($content, $matchedColumnHeaders)) { + $information = array_search($content, $matchedColumnHeaders); + $headers[$key] = $information; + $this->logger->notice("Matched {$information} on column {$key} (displayed in the file as '{$content}')"); + } else { + $this->logger->notice("Column with content '{$content}' is ignored"); + } + } + + return $headers; + } + + /** + * Process a text type on a custom field. + * + * @param type $value + * + * @return type + */ + protected function processTextType( + $value, + \Symfony\Component\Form\FormInterface $form, + \Chill\CustomFieldsBundle\Entity\CustomField $cf + ) { + $form->submit([$cf->getSlug() => $value]); + + $value = $form->getData()[$cf->getSlug()]; + + $this->logger->debug(sprintf('Found value : %s for custom field with question ' + . "'%s'", $value, $this->helper->localize($cf->getName()))); + + return $value; + } + /** * Recursive method to collect the possibles answer from a ChoiceType (or * its inherited types). * - * @param \Symfony\Component\Form\FormInterface $form + * @param mixed $choices + * + * @throws Exception + * * @return array where - * @throws \Exception */ private function collectChoicesAnswers($choices) { - $answers = array(); - + $answers = []; + /* @var $choice \Symfony\Component\Form\ChoiceList\View\ChoiceView */ - foreach($choices as $choice) { + foreach ($choices as $choice) { if ($choice instanceof \Symfony\Component\Form\ChoiceList\View\ChoiceView) { $answers[$choice->value] = $choice->label; } elseif ($choice instanceof \Symfony\Component\Form\ChoiceList\View\ChoiceGroupView) { $answers = $answers + $this->collectChoicesAnswers($choice->choices); } else { - throw new \Exception(sprintf( - "The choice type is not know. Expected '%s' or '%s', get '%s'", - \Symfony\Component\Form\ChoiceList\View\ChoiceView::class, - \Symfony\Component\Form\ChoiceList\View\ChoiceGroupView::class, - get_class($choice) - )); + throw new Exception(sprintf( + "The choice type is not know. Expected '%s' or '%s', get '%s'", + \Symfony\Component\Form\ChoiceList\View\ChoiceView::class, + \Symfony\Component\Form\ChoiceList\View\ChoiceGroupView::class, + get_class($choice) + )); } } - + return $answers; } - - /** - * @param $value - * @param $formats - * @return bool|\DateTime - */ - protected function processDate($value, $formats) - { - $possibleFormats = explode("|", $formats); - - foreach($possibleFormats as $format) { - $this->logger->debug("Trying format $format", array(__METHOD__)); - $dateR = strptime($value, $format); - - if (is_array($dateR) && $dateR['unparsed'] === '') { - $string = sprintf("%04d-%02d-%02d %02d:%02d:%02d", - ($dateR['tm_year']+1900), - ($dateR['tm_mon']+1), - ($dateR['tm_mday']), - ($dateR['tm_hour']), - ($dateR['tm_min']), - ($dateR['tm_sec'])); - $date = \DateTime::createFromFormat("Y-m-d H:i:s", $string); - $this->logger->debug(sprintf("Interpreting %s as date %s", $value, $date->format("Y-m-d H:i:s"))); - - return $date; - } - } - - // if we arrive here, we could not process the date - $this->logger->debug(sprintf( - "Line %d : a date could not be interpreted. Was %s.", - $this->line, - $value)); - - return false; - } - - } diff --git a/src/Bundle/ChillPersonBundle/Config/ConfigPersonAltNamesHelper.php b/src/Bundle/ChillPersonBundle/Config/ConfigPersonAltNamesHelper.php index 92c093385..dfbce37a7 100644 --- a/src/Bundle/ChillPersonBundle/Config/ConfigPersonAltNamesHelper.php +++ b/src/Bundle/ChillPersonBundle/Config/ConfigPersonAltNamesHelper.php @@ -1,61 +1,54 @@ config = $config; } - + /** - * Return true if at least one alt name is configured - * - * @return bool - */ - public function hasAltNames(): bool - { - return count($this->config) > 0; - } - - /** - * get the choices as key => values - * - * @return array + * get the choices as key => values. */ public function getChoices(): array { $choices = []; + foreach ($this->config as $entry) { - $labels = $entry['labels']; $lang = false; $label = false; $cur = reset($labels); + while ($cur) { if (key($labels) === 'lang') { $lang = current($labels); } - + if (key($labels) === 'label') { $label = current($labels); } - - if ($lang !== FALSE && $label !== FALSE) { + + if (false !== $lang && false !== $label) { $choices[$entry['key']][$lang] = $label; $lang = false; $label = false; @@ -63,8 +56,15 @@ class ConfigPersonAltNamesHelper $cur = next($labels); } } - + return $choices; } + /** + * Return true if at least one alt name is configured. + */ + public function hasAltNames(): bool + { + return count($this->config) > 0; + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index bbf2f399a..ded054f18 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -1,17 +1,24 @@ eventDispatcher = $eventDispatcher; $this->validator = $validator; } - + public function participationApi($id, Request $request, $_format) { - /** @var AccompanyingPeriod $accompanyingPeriod */ + /** @var AccompanyingPeriod $accompanyingPeriod */ $accompanyingPeriod = $this->getEntity('participation', $id, $request); $person = $this->getSerializer() ->deserialize($request->getContent(), Person::class, $_format, []); - if (NULL === $person) { + if (null === $person) { throw new BadRequestException('person id not found'); } @@ -43,13 +50,17 @@ class AccompanyingCourseApiController extends ApiController switch ($request->getMethod()) { case Request::METHOD_POST: $participation = $accompanyingPeriod->addPerson($person); + break; + case Request::METHOD_DELETE: $participation = $accompanyingPeriod->removePerson($person); - $participation->setEndDate(new \DateTimeImmutable('now')); + $participation->setEndDate(new DateTimeImmutable('now')); + break; + default: - throw new BadRequestException("This method is not supported"); + throw new BadRequestException('This method is not supported'); } $errors = $this->validator->validate($accompanyingPeriod); @@ -70,7 +81,7 @@ class AccompanyingCourseApiController extends ApiController AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, new AccompanyingPeriodPrivacyEvent($entity, [ 'action' => $action, - 'request' => $request->getMethod() + 'request' => $request->getMethod(), ]) ); diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php index 05a1934e6..c367da6be 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php @@ -1,36 +1,36 @@ dispatcher = $dispatcher; $this->validator = $validator; } - /** - * Homepage of Accompanying Course section - * - * @Route("/{_locale}/parcours/{accompanying_period_id}", name="chill_person_accompanying_course_index") - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) - */ - public function indexAction(AccompanyingPeriod $accompanyingCourse): Response - { - return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [ - 'accompanyingCourse' => $accompanyingCourse - ]); - } /** - * Show page of Accompanying Course section - * - * the page show all blocks except one active edit block, managed by vuejs component - * that's why title of page is 'edit accompanying course' - * - * @Route("/{_locale}/parcours/{accompanying_period_id}/show", name="chill_person_accompanying_course_show") - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) - */ - public function showAction(AccompanyingPeriod $accompanyingCourse): Response - { - return $this->render('@ChillPerson/AccompanyingCourse/show.html.twig', [ - 'accompanyingCourse' => $accompanyingCourse - ]); - } - - /** - * History page of Accompanying Course section + * History page of Accompanying Course section. * * the page show anti chronologic history with all actions, title of page is 'accompanying course details' * @@ -82,66 +54,53 @@ class AccompanyingCourseController extends Controller public function historyAction(AccompanyingPeriod $accompanyingCourse): Response { return $this->render('@ChillPerson/AccompanyingCourse/history.html.twig', [ - 'accompanyingCourse' => $accompanyingCourse + 'accompanyingCourse' => $accompanyingCourse, ]); } /** - * Get API Data for showing endpoint + * Homepage of Accompanying Course section. * - * @Route( - * "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/show.{_format}", - * name="chill_person_accompanying_course_api_show" - * ) + * @Route("/{_locale}/parcours/{accompanying_period_id}", name="chill_person_accompanying_course_index") * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) */ - public function showAPI(AccompanyingPeriod $accompanyingCourse, $_format): Response + public function indexAction(AccompanyingPeriod $accompanyingCourse): Response { - // TODO check ACL on AccompanyingPeriod - - $this->dispatcher->dispatch( - AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, - new AccompanyingPeriodPrivacyEvent($accompanyingCourse, [ - 'action' => 'showApi' - ]) - ); - - switch ($_format) { - case 'json': - return $this->json($accompanyingCourse); - default: - throw new BadRequestException('Unsupported format'); - } - + return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [ + 'accompanyingCourse' => $accompanyingCourse, + ]); } /** - * Get API Data for showing endpoint + * Get API Data for showing endpoint. * * @Route( * "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/participation.{_format}", * name="chill_person_accompanying_course_api_add_participation", - * methods={"POST","DELETE"}, + * methods={"POST", "DELETE"}, * format="json", * requirements={ * "_format": "json", * } * ) * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + * + * @param mixed $_format */ public function participationAPI(Request $request, AccompanyingPeriod $accompanyingCourse, $_format): Response { switch ($_format) { case 'json': $person = $this->serializer->deserialize($request->getContent(), Person::class, $_format, [ - ]); + break; + default: throw new BadRequestException('Unsupported format'); } - if (NULL === $person) { + if (null === $person) { throw new BadRequestException('person id not found'); } @@ -160,4 +119,51 @@ class AccompanyingCourseController extends Controller return $this->json($participation); } + + /** + * Show page of Accompanying Course section. + * + * the page show all blocks except one active edit block, managed by vuejs component + * that's why title of page is 'edit accompanying course' + * + * @Route("/{_locale}/parcours/{accompanying_period_id}/show", name="chill_person_accompanying_course_show") + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + */ + public function showAction(AccompanyingPeriod $accompanyingCourse): Response + { + return $this->render('@ChillPerson/AccompanyingCourse/show.html.twig', [ + 'accompanyingCourse' => $accompanyingCourse, + ]); + } + + /** + * Get API Data for showing endpoint. + * + * @Route( + * "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/show.{_format}", + * name="chill_person_accompanying_course_api_show" + * ) + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + * + * @param mixed $_format + */ + public function showAPI(AccompanyingPeriod $accompanyingCourse, $_format): Response + { + // TODO check ACL on AccompanyingPeriod + + $this->dispatcher->dispatch( + AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, + new AccompanyingPeriodPrivacyEvent($accompanyingCourse, [ + 'action' => 'showApi', + ]) + ); + + switch ($_format) { + case 'json': + return $this->json($accompanyingCourse); + + default: + throw new BadRequestException('Unsupported format'); + } + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php index 5c862ee4f..80d3d666a 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodController.php @@ -1,35 +1,23 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Controller; -use Chill\PersonBundle\Privacy\PrivacyEvent; -use Doctrine\DBAL\Exception; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Form\AccompanyingPeriodType; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\Common\Collections\Criteria; +use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\PersonBundle\Security\Authorization\PersonVoter; +use DateTime; +use Doctrine\Common\Collections\Criteria; +use Doctrine\DBAL\Exception; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -37,9 +25,7 @@ use Symfony\Component\Validator\ConstraintViolationListInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; /** - * Class AccompanyingPeriodController - * - * @package Chill\PersonBundle\Controller + * Class AccompanyingPeriodController. */ class AccompanyingPeriodController extends AbstractController { @@ -47,230 +33,86 @@ class AccompanyingPeriodController extends AbstractController * @var EventDispatcherInterface */ protected $eventDispatcher; - + /** * @var ValidatorInterface */ protected $validator; - + /** * AccompanyingPeriodController constructor. - * - * @param EventDispatcherInterface $eventDispatcher - * @param ValidatorInterface $validator */ public function __construct(EventDispatcherInterface $eventDispatcher, ValidatorInterface $validator) { $this->eventDispatcher = $eventDispatcher; $this->validator = $validator; } - - public function listAction(int $person_id): Response - { - $person = $this->_getPerson($person_id); - - $event = new PrivacyEvent($person, [ - 'element_class' => AccompanyingPeriod::class, - 'action' => 'list' - ]); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - return $this->render('ChillPersonBundle:AccompanyingPeriod:list.html.twig', [ - 'accompanying_periods' => $person->getAccompanyingPeriodsOrdered(), - 'person' => $person - ]); - } - - public function createAction(int $person_id, Request $request): Response - { - $person = $this->_getPerson($person_id); - - $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, - 'You are not allowed to update this person'); - - $accompanyingPeriod = new AccompanyingPeriod(new \DateTime('now')); - $accompanyingPeriod->setClosingDate(new \DateTime('now')); - - $accompanyingPeriod->addPerson($person); - //or $person->addAccompanyingPeriod($accompanyingPeriod); - - $form = $this->createForm( - AccompanyingPeriodType::class, - $accompanyingPeriod, [ - 'period_action' => 'create', - 'center' => $person->getCenter() - ]); - - if ($request->getMethod() === 'POST') { - $form->handleRequest($request); - $errors = $this->_validatePerson($person); - $flashBag = $this->get('session')->getFlashBag(); - - if ($form->isValid(['Default', 'closed']) - && count($errors) === 0) { - - $em = $this->getDoctrine()->getManager(); - $em->persist($accompanyingPeriod); - $em->flush(); - $flashBag->add('success', - $this->get('translator')->trans( - 'A period has been created.')); - - return $this->redirect( - $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() - ])); - - } else { - $flashBag->add('error', $this->get('translator') - ->trans('Error! Period not created!')); - - foreach($errors as $error) { - $flashBag->add('info', $error->getMessage()); - } - } - } - - return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ - 'form' => $form->createView(), - 'person' => $person, - 'accompanying_period' => $accompanyingPeriod - ]); - } - - /** - * @throws Exception - */ - public function updateAction(int $person_id, int $period_id, Request $request): Response - { - $em = $this->getDoctrine()->getManager(); - - /** @var AccompanyingPeriod $accompanyingPeriod */ - $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($period_id); - - if ($accompanyingPeriod === null) { - throw $this->createNotFoundException("Period with id " . $period_id . " is not found"); - } - - /** @var Person $person */ - $person = $this->_getPerson($person_id); - - // CHECK - if (! $accompanyingPeriod->containsPerson($person)) { - throw new Exception("Accompanying period " . $period_id . " does not contain person " . $person_id); - } - - $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, - 'You are not allowed to update this person'); - - $form = $this->createForm(AccompanyingPeriodType::class, - $accompanyingPeriod, [ - 'period_action' => 'update', - 'center' => $person->getCenter() - ]); - - if ($request->getMethod() === 'POST') { - $form->handleRequest($request); - $errors = $this->_validatePerson($person); - $flashBag = $this->get('session')->getFlashBag(); - - if ($form->isValid(['Default', 'closed']) - && count($errors) === 0) { - - $em->flush(); - - $flashBag->add('success', - $this->get('translator')->trans('An accompanying period has been updated.')); - - return $this->redirect( - $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() - ])); - - } else { - - $flashBag->add('error', $this->get('translator') - ->trans('Error when updating the period')); - - foreach($errors as $error) { - $flashBag->add('info', $error->getMessage()); - } - } - } - - return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ - 'form' => $form->createView(), - 'person' => $person, - 'accompanying_period' => $accompanyingPeriod - ]); - } - /** * @throws \Exception */ public function closeAction(int $person_id, Request $request): Response { - $person = $this->_getPerson($person_id); $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, 'You are not allowed to update this person'); if ($person->isOpen() === false) { - $this->get('session')->getFlashBag() ->add('error', $this->get('translator') - ->trans('Beware period is closed', ['%name%' => $person->__toString()] - )); + ->trans( + 'Beware period is closed', + ['%name%' => $person->__toString()] + )); return $this->redirect( $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() - ])); + 'person_id' => $person->getId(), + ]) + ); } $current = $person->getCurrentAccompanyingPeriod(); - + $form = $this->createForm(AccompanyingPeriodType::class, $current, [ 'period_action' => 'close', - 'center' => $person->getCenter() + 'center' => $person->getCenter(), ]); if ($request->getMethod() === 'POST') { $form->handleRequest($request); - if ($form->isValid()){ + if ($form->isValid()) { $person->close($current); $errors = $this->_validatePerson($person); if (count($errors) === 0) { $this->get('session')->getFlashBag() ->add('success', $this->get('translator') - ->trans('An accompanying period has been closed.', [ - '%name%' => $person->__toString() - ])); + ->trans('An accompanying period has been closed.', [ + '%name%' => $person->__toString(), + ])); $this->getDoctrine()->getManager()->flush(); return $this->redirect( $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() + 'person_id' => $person->getId(), ]) ); - - } else { - $this->get('session')->getFlashBag() - ->add('error', $this->get('translator') - ->trans('Error! Period not closed!')); - - foreach ($errors as $error) { - $this->get('session')->getFlashBag() - ->add('info', $error->getMessage()); - } } - + $this->get('session')->getFlashBag() + ->add('error', $this->get('translator') + ->trans('Error! Period not closed!')); + + foreach ($errors as $error) { + $this->get('session')->getFlashBag() + ->add('info', $error->getMessage()); + } } else { //if form is not valid $this->get('session')->getFlashBag() - ->add('error', + ->add( + 'error', $this->get('translator') ->trans('Pediod closing form is not valid') ); @@ -285,57 +127,127 @@ class AccompanyingPeriodController extends AbstractController return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ 'form' => $form->createView(), 'person' => $person, - 'accompanying_period' => $current + 'accompanying_period' => $current, ]); } - - private function _validatePerson(Person $person): ConstraintViolationListInterface - { - $errors = $this->validator->validate($person, null, - ['Default']); - // Can be disabled with config - if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) { - - $errors_accompanying_period = $this->validator->validate($person, null, - ['accompanying_period_consistent']); - - foreach($errors_accompanying_period as $error ) { - $errors->add($error); + public function createAction(int $person_id, Request $request): Response + { + $person = $this->_getPerson($person_id); + + $this->denyAccessUnlessGranted( + PersonVoter::UPDATE, + $person, + 'You are not allowed to update this person' + ); + + $accompanyingPeriod = new AccompanyingPeriod(new DateTime('now')); + $accompanyingPeriod->setClosingDate(new DateTime('now')); + + $accompanyingPeriod->addPerson($person); + //or $person->addAccompanyingPeriod($accompanyingPeriod); + + $form = $this->createForm( + AccompanyingPeriodType::class, + $accompanyingPeriod, + [ + 'period_action' => 'create', + 'center' => $person->getCenter(), + ] + ); + + if ($request->getMethod() === 'POST') { + $form->handleRequest($request); + $errors = $this->_validatePerson($person); + $flashBag = $this->get('session')->getFlashBag(); + + if ( + $form->isValid(['Default', 'closed']) + && count($errors) === 0 + ) { + $em = $this->getDoctrine()->getManager(); + $em->persist($accompanyingPeriod); + $em->flush(); + $flashBag->add( + 'success', + $this->get('translator')->trans( + 'A period has been created.' + ) + ); + + return $this->redirect( + $this->generateUrl('chill_person_accompanying_period_list', [ + 'person_id' => $person->getId(), + ]) + ); + } + $flashBag->add('error', $this->get('translator') + ->trans('Error! Period not created!')); + + foreach ($errors as $error) { + $flashBag->add('info', $error->getMessage()); } } - return $errors; + return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ + 'form' => $form->createView(), + 'person' => $person, + 'accompanying_period' => $accompanyingPeriod, + ]); } - + + public function listAction(int $person_id): Response + { + $person = $this->_getPerson($person_id); + + $event = new PrivacyEvent($person, [ + 'element_class' => AccompanyingPeriod::class, + 'action' => 'list', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillPersonBundle:AccompanyingPeriod:list.html.twig', [ + 'accompanying_periods' => $person->getAccompanyingPeriodsOrdered(), + 'person' => $person, + ]); + } + public function openAction(int $person_id, Request $request): Response { $person = $this->_getPerson($person_id); - $this->denyAccessUnlessGranted(PersonVoter::UPDATE, $person, - 'You are not allowed to update this person'); + $this->denyAccessUnlessGranted( + PersonVoter::UPDATE, + $person, + 'You are not allowed to update this person' + ); //in case the person is already open if ($person->isOpen()) { $this->get('session')->getFlashBag() ->add('error', $this->get('translator') - ->trans('Error! Period %name% is not closed ; it can be open', - ['%name%' => $person->__toString()] - )); + ->trans( + 'Error! Period %name% is not closed ; it can be open', + ['%name%' => $person->__toString()] + )); return $this->redirect( $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() - ])); + 'person_id' => $person->getId(), + ]) + ); } - $accompanyingPeriod = new AccompanyingPeriod(new \DateTime()); + $accompanyingPeriod = new AccompanyingPeriod(new DateTime()); - $form = $this->createForm(AccompanyingPeriodType::class, - $accompanyingPeriod, [ + $form = $this->createForm( + AccompanyingPeriodType::class, + $accompanyingPeriod, + [ 'period_action' => 'open', - 'center' => $person->getCenter() - ]); + 'center' => $person->getCenter(), + ] + ); if ($request->getMethod() === 'POST') { $form->handleRequest($request); @@ -348,43 +260,44 @@ class AccompanyingPeriodController extends AbstractController if (count($errors) <= 0) { $this->get('session')->getFlashBag() ->add('success', $this->get('translator') - ->trans('An accompanying period has been opened.', + ->trans( + 'An accompanying period has been opened.', ['%name%' => $person->__toString()] - )); + )); $this->getDoctrine()->getManager()->flush(); return $this->redirect( $this->generateUrl('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() - ])); - - } else { - $this->get('session')->getFlashBag() - ->add('error', $this->get('translator') - ->trans('Period not opened')); - - foreach ($errors as $error) { - $this->get('session')->getFlashBag() - ->add('info', $error->getMessage()); - } + 'person_id' => $person->getId(), + ]) + ); } + $this->get('session')->getFlashBag() + ->add('error', $this->get('translator') + ->trans('Period not opened')); + foreach ($errors as $error) { + $this->get('session')->getFlashBag() + ->add('info', $error->getMessage()); + } } else { // if errors in forms $this->get('session')->getFlashBag() - ->add('error', $this->get('translator') - ->trans('Period not opened : form is invalid') - ); + ->add( + 'error', + $this->get('translator') + ->trans('Period not opened : form is invalid') + ); } } return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ 'form' => $form->createView(), 'person' => $person, - 'accompanying_period' => $accompanyingPeriod + 'accompanying_period' => $accompanyingPeriod, ]); } - + public function reOpenAction(int $person_id, int $period_id, Request $request): Response { /** @var Person $person */ @@ -395,16 +308,16 @@ class AccompanyingPeriodController extends AbstractController /* @var $period AccompanyingPeriod */ $period = $person->getAccompanyingPeriods() - ->matching($criteria) - ->first(); + ->matching($criteria) + ->first(); - if ($period === NULL) { + if (null === $period) { throw $this->createNotFoundException('period not found'); } $confirm = $request->query->getBoolean('confirm', false); - if ($confirm === true && $period->canBeReOpened($person)) { + if (true === $confirm && $period->canBeReOpened($person)) { $period->reOpen(); $this->_validatePerson($person); @@ -412,40 +325,143 @@ class AccompanyingPeriodController extends AbstractController $this->getDoctrine()->getManager()->flush(); $this->addFlash('success', $this->get('translator')->trans( - 'The period has been re-opened')); + 'The period has been re-opened' + )); return $this->redirectToRoute('chill_person_accompanying_period_list', [ - 'person_id' => $person->getId() + 'person_id' => $person->getId(), ]); - - } elseif ($confirm === false && $period->canBeReOpened($person)) { + } + + if (false === $confirm && $period->canBeReOpened($person)) { return $this->render('ChillPersonBundle:AccompanyingPeriod:re_open.html.twig', [ 'period' => $period, - 'person' => $person + 'person' => $person, ]); - - } else { - return (new Response()) - ->setStatusCode(Response::HTTP_BAD_REQUEST) - ->setContent("You cannot re-open this period"); } + + return (new Response()) + ->setStatusCode(Response::HTTP_BAD_REQUEST) + ->setContent('You cannot re-open this period'); + } + + /** + * @throws Exception + */ + public function updateAction(int $person_id, int $period_id, Request $request): Response + { + $em = $this->getDoctrine()->getManager(); + + /** @var AccompanyingPeriod $accompanyingPeriod */ + $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($period_id); + + if (null === $accompanyingPeriod) { + throw $this->createNotFoundException('Period with id ' . $period_id . ' is not found'); + } + + /** @var Person $person */ + $person = $this->_getPerson($person_id); + + // CHECK + if (!$accompanyingPeriod->containsPerson($person)) { + throw new Exception('Accompanying period ' . $period_id . ' does not contain person ' . $person_id); + } + + $this->denyAccessUnlessGranted( + PersonVoter::UPDATE, + $person, + 'You are not allowed to update this person' + ); + + $form = $this->createForm( + AccompanyingPeriodType::class, + $accompanyingPeriod, + [ + 'period_action' => 'update', + 'center' => $person->getCenter(), + ] + ); + + if ($request->getMethod() === 'POST') { + $form->handleRequest($request); + $errors = $this->_validatePerson($person); + $flashBag = $this->get('session')->getFlashBag(); + + if ( + $form->isValid(['Default', 'closed']) + && count($errors) === 0 + ) { + $em->flush(); + + $flashBag->add( + 'success', + $this->get('translator')->trans('An accompanying period has been updated.') + ); + + return $this->redirect( + $this->generateUrl('chill_person_accompanying_period_list', [ + 'person_id' => $person->getId(), + ]) + ); + } + + $flashBag->add('error', $this->get('translator') + ->trans('Error when updating the period')); + + foreach ($errors as $error) { + $flashBag->add('info', $error->getMessage()); + } + } + + return $this->render('ChillPersonBundle:AccompanyingPeriod:form.html.twig', [ + 'form' => $form->createView(), + 'person' => $person, + 'accompanying_period' => $accompanyingPeriod, + ]); } /** * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */ - private function _getPerson(int $id) : Person + private function _getPerson(int $id): Person { $person = $this->getDoctrine()->getManager() ->getRepository('ChillPersonBundle:Person')->find($id); - if ($person === null) { + if (null === $person) { throw $this->createNotFoundException('Person not found'); } - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person, - "You are not allowed to see this person"); + $this->denyAccessUnlessGranted( + PersonVoter::SEE, + $person, + 'You are not allowed to see this person' + ); return $person; } + + private function _validatePerson(Person $person): ConstraintViolationListInterface + { + $errors = $this->validator->validate( + $person, + null, + ['Default'] + ); + + // Can be disabled with config + if (false === $this->container->getParameter('chill_person.allow_multiple_simultaneous_accompanying_periods')) { + $errors_accompanying_period = $this->validator->validate( + $person, + null, + ['accompanying_period_consistent'] + ); + + foreach ($errors_accompanying_period as $error) { + $errors->add($error); + } + } + + return $errors; + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/AdminClosingMotiveController.php b/src/Bundle/ChillPersonBundle/Controller/AdminClosingMotiveController.php index 483619be6..ac3ef7506 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AdminClosingMotiveController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AdminClosingMotiveController.php @@ -1,50 +1,51 @@ query->has('parent_id')) { $parentId = $request->query->getInt('parent_id'); - + $parent = $this->getDoctrine()->getManager() ->getRepository($this->getEntityClass()) ->find($parentId); - - if (NULL === $parent) { + + if (null === $parent) { throw $this->createNotFoundException('parent id not found'); } - + $entity->setParent($parent); } + return $entity; } - + /** - * @param string $action * @param \Doctrine\ORM\QueryBuilder|mixed $query - * @param Request $request - * @param PaginatorInterface $paginator + * * @return \Doctrine\ORM\QueryBuilder|mixed */ protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator) diff --git a/src/Bundle/ChillPersonBundle/Controller/AdminController.php b/src/Bundle/ChillPersonBundle/Controller/AdminController.php index 751beb7a8..4496fc5a8 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AdminController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AdminController.php @@ -1,26 +1,31 @@ render('ChillPersonBundle:Admin:layout.html.twig', []); } - + /** * @return \Symfony\Component\HttpFoundation\RedirectResponse */ diff --git a/src/Bundle/ChillPersonBundle/Controller/AdminMaritalStatusController.php b/src/Bundle/ChillPersonBundle/Controller/AdminMaritalStatusController.php index da46ac5c5..4f0402402 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AdminMaritalStatusController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AdminMaritalStatusController.php @@ -1,15 +1,20 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Symfony\Component\HttpFoundation\JsonResponse; - class ApiPersonController extends Controller { - public function viewAction($id, $_format) + public function viewAction($id, $_format) { - } } diff --git a/src/Bundle/ChillPersonBundle/Controller/OpeningApiController.php b/src/Bundle/ChillPersonBundle/Controller/OpeningApiController.php index 3b44162c4..78f85b952 100644 --- a/src/Bundle/ChillPersonBundle/Controller/OpeningApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/OpeningApiController.php @@ -1,10 +1,17 @@ where($qb->expr()->gt('e.noActiveAfter', ':now')) ->orWhere($qb->expr()->isNull('e.noActiveAfter')); - $qb->setParameter('now', new \DateTime('now')); - } + $qb->setParameter('now', new DateTime('now')); + } } diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php b/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php index f68e1ee9b..6ef6d9fee 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonAddressController.php @@ -1,43 +1,26 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Form\Type\AddressType; +use Chill\PersonBundle\Entity\Person; +use Doctrine\Common\Collections\Criteria; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Form\Type\AddressType; -use Chill\MainBundle\Entity\Address; -use Doctrine\Common\Collections\Criteria; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Validator\Validator\ValidatorInterface; /** * Class PersonAddressController - * Controller for addresses associated with person - * - * @package Chill\PersonBundle\Controller - * @author Julien Fastré - * @author Champs Libres + * Controller for addresses associated with person. */ class PersonAddressController extends AbstractController { @@ -45,81 +28,30 @@ class PersonAddressController extends AbstractController * @var ValidatorInterface */ protected $validator; - + /** * PersonAddressController constructor. - * - * @param ValidatorInterface $validator */ public function __construct(ValidatorInterface $validator) { $this->validator = $validator; } - - public function listAction($person_id) - { - $person = $this->getDoctrine()->getManager() - ->getRepository('ChillPersonBundle:Person') - ->find($person_id); - - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found "); - } - - $this->denyAccessUnlessGranted( - 'CHILL_PERSON_SEE', - $person, - "You are not allowed to edit this person." - ); - - return $this->render('ChillPersonBundle:Address:list.html.twig', array( - 'person' => $person - )); - } - - public function newAction($person_id) - { - $person = $this->getDoctrine()->getManager() - ->getRepository('ChillPersonBundle:Person') - ->find($person_id); - - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found "); - } - - $this->denyAccessUnlessGranted( - 'CHILL_PERSON_UPDATE', - $person, - "You are not allowed to edit this person." - ); - - $address = new Address(); - - $form = $this->createCreateForm($person, $address); - - return $this->render('ChillPersonBundle:Address:new.html.twig', array( - 'person' => $person, - 'form' => $form->createView() - )); - } public function createAction($person_id, Request $request) { $person = $this->getDoctrine()->getManager() - ->getRepository('ChillPersonBundle:Person') - ->find($person_id); + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found "); + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found '); } $this->denyAccessUnlessGranted( 'CHILL_PERSON_UPDATE', $person, - "You are not allowed to edit this person." + 'You are not allowed to edit this person.' ); $address = new Address(); @@ -137,7 +69,6 @@ class PersonAddressController extends AbstractController $this->addFlash('error', $error->getMessage()); } } elseif ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); $em->flush(); @@ -146,47 +77,96 @@ class PersonAddressController extends AbstractController $this->get('translator')->trans('The new address was created successfully') ); - return $this->redirectToRoute('chill_person_address_list', array( - 'person_id' => $person->getId() - )); + return $this->redirectToRoute('chill_person_address_list', [ + 'person_id' => $person->getId(), + ]); } else { $this->addFlash('error', $this->get('translator') - ->trans('Error! Address not created!')); + ->trans('Error! Address not created!')); } } - return $this->render('ChillPersonBundle:Address:new.html.twig', array( + return $this->render('ChillPersonBundle:Address:new.html.twig', [ 'person' => $person, - 'form' => $form->createView() - )); + 'form' => $form->createView(), + ]); } public function editAction($person_id, $address_id) { $person = $this->getDoctrine()->getManager() - ->getRepository('ChillPersonBundle:Person') - ->find($person_id); + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found "); + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found '); } $this->denyAccessUnlessGranted( 'CHILL_PERSON_UPDATE', $person, - "You are not allowed to edit this person." + 'You are not allowed to edit this person.' ); $address = $this->findAddressById($person, $address_id); $form = $this->createEditForm($person, $address); - return $this->render('ChillPersonBundle:Address:edit.html.twig', array( - 'person' => $person, - 'address' => $address, - 'form' => $form->createView() - )); + return $this->render('ChillPersonBundle:Address:edit.html.twig', [ + 'person' => $person, + 'address' => $address, + 'form' => $form->createView(), + ]); + } + + public function listAction($person_id) + { + $person = $this->getDoctrine()->getManager() + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found '); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_SEE', + $person, + 'You are not allowed to edit this person.' + ); + + return $this->render('ChillPersonBundle:Address:list.html.twig', [ + 'person' => $person, + ]); + } + + public function newAction($person_id) + { + $person = $this->getDoctrine()->getManager() + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found '); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_UPDATE', + $person, + 'You are not allowed to edit this person.' + ); + + $address = new Address(); + + $form = $this->createCreateForm($person, $address); + + return $this->render('ChillPersonBundle:Address:new.html.twig', [ + 'person' => $person, + 'form' => $form->createView(), + ]); } public function updateAction($person_id, $address_id, Request $request) @@ -195,15 +175,15 @@ class PersonAddressController extends AbstractController ->getRepository('ChillPersonBundle:Person') ->find($person_id); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found "); + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found '); } $this->denyAccessUnlessGranted( 'CHILL_PERSON_UPDATE', $person, - "You are not allowed to edit this person." + 'You are not allowed to edit this person.' ); $address = $this->findAddressById($person, $address_id); @@ -220,92 +200,87 @@ class PersonAddressController extends AbstractController } } elseif ($form->isValid()) { $this->getDoctrine()->getManager() - ->flush(); + ->flush(); $this->addFlash('success', $this->get('translator')->trans( - "The address has been successfully updated" + 'The address has been successfully updated' )); - return $this->redirectToRoute('chill_person_address_list', array( - 'person_id' => $person->getId() - )); + return $this->redirectToRoute('chill_person_address_list', [ + 'person_id' => $person->getId(), + ]); } else { $this->addFlash('error', $this->get('translator') ->trans('Error when updating the period')); } } - return $this->render('ChillPersonBundle:Address:edit.html.twig', array( - 'person' => $person, - 'address' => $address, - 'form' => $form->createView() - )); + return $this->render('ChillPersonBundle:Address:edit.html.twig', [ + 'person' => $person, + 'address' => $address, + 'form' => $form->createView(), + ]); } /** - * @param Person $person - * @param Address $address - * @return \Symfony\Component\Form\Form - */ - protected function createEditForm(Person $person, Address $address) - { - $form = $this->createForm(AddressType::class, $address, array( - 'method' => 'POST', - 'action' => $this->generateUrl('chill_person_address_update', array( - 'person_id' => $person->getId(), - 'address_id' => $address->getId() - )), - 'has_no_address' => true - )); - - $form->add('submit', SubmitType::class, array( - 'label' => 'Submit' - )); - - return $form; - } - - /** - * - * @param Person $person - * @param Address $address * @return \Symfony\Component\Form\Form */ protected function createCreateForm(Person $person, Address $address) { - $form = $this->createForm(AddressType::class, $address, array( - 'method' => 'POST', - 'action' => $this->generateUrl('chill_person_address_create', array( - 'person_id' => $person->getId() - )), - 'has_no_address' => true - )); + $form = $this->createForm(AddressType::class, $address, [ + 'method' => 'POST', + 'action' => $this->generateUrl('chill_person_address_create', [ + 'person_id' => $person->getId(), + ]), + 'has_no_address' => true, + ]); - $form->add('submit', SubmitType::class, array( - 'label' => 'Submit' - )); + $form->add('submit', SubmitType::class, [ + 'label' => 'Submit', + ]); + + return $form; + } + + /** + * @return \Symfony\Component\Form\Form + */ + protected function createEditForm(Person $person, Address $address) + { + $form = $this->createForm(AddressType::class, $address, [ + 'method' => 'POST', + 'action' => $this->generateUrl('chill_person_address_update', [ + 'person_id' => $person->getId(), + 'address_id' => $address->getId(), + ]), + 'has_no_address' => true, + ]); + + $form->add('submit', SubmitType::class, [ + 'label' => 'Submit', + ]); return $form; } /** - * - * @param Person $person * @param int $address_id - * @return Address + * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the address id does not exists or is not associated with given person + * + * @return Address */ protected function findAddressById(Person $person, $address_id) { // filtering address $criteria = Criteria::create() - ->where(Criteria::expr()->eq('id', $address_id)) - ->setMaxResults(1); + ->where(Criteria::expr()->eq('id', $address_id)) + ->setMaxResults(1); $addresses = $person->getAddresses()->matching($criteria); if (count($addresses) === 0) { - throw $this->createNotFoundException("Address with id $address_id " - . "matching person $person_id not found "); + throw $this->createNotFoundException("Address with id {$address_id} " + . "matching person {$person_id} not found "); } return $addresses->first(); @@ -313,16 +288,17 @@ class PersonAddressController extends AbstractController /** * @param Chill\PersonBundle\Entity\Person $person + * * @return \Symfony\Component\Validator\ConstraintViolationListInterface */ private function validatePerson(Person $person) { $errors = $this->validator - ->validate($person, null, array('Default')); + ->validate($person, null, ['Default']); $errors_addresses_consistent = $this->validator - ->validate($person, null, array('addresses_consistent')); + ->validate($person, null, ['addresses_consistent']); - foreach($errors_addresses_consistent as $error) { + foreach ($errors_addresses_consistent as $error) { $errors->add($error); } diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonController.php b/src/Bundle/ChillPersonBundle/Controller/PersonController.php index bfb32654e..e02b0a7ac 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonController.php @@ -1,57 +1,37 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Controller; -use Chill\PersonBundle\Privacy\PrivacyEvent; -use Psr\Log\LoggerInterface; +use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Form\PersonType; use Chill\PersonBundle\Form\CreationPersonType; +use Chill\PersonBundle\Form\PersonType; +use Chill\PersonBundle\Privacy\PrivacyEvent; +use Chill\PersonBundle\Repository\PersonRepository; +use Chill\PersonBundle\Search\SimilarPersonMatcher; +use DateTime; +use Doctrine\ORM\EntityManagerInterface; +use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\PersonBundle\Search\SimilarPersonMatcher; use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Search\SearchProvider; -use Chill\PersonBundle\Repository\PersonRepository; -use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; use Symfony\Component\Validator\Validator\ValidatorInterface; -use Doctrine\ORM\EntityManagerInterface; final class PersonController extends AbstractController { /** - * @var SimilarPersonMatcher + * @var ConfigPersonAltNamesHelper */ - protected $similarPersonMatcher; - - /** - * @var TranslatorInterface - */ - protected $translator; + protected $configPersonAltNameHelper; /** * @var EventDispatcherInterface @@ -64,9 +44,14 @@ final class PersonController extends AbstractController protected $personRepository; /** - * @var ConfigPersonAltNamesHelper + * @var SimilarPersonMatcher */ - protected $configPersonAltNameHelper; + protected $similarPersonMatcher; + + /** + * @var TranslatorInterface + */ + protected $translator; /** * @var EntityManagerInterface @@ -101,145 +86,290 @@ final class PersonController extends AbstractController $this->logger = $logger; $this->validator = $validator; $this->em = $em; - } - - public function getCFGroup() - { - $cFGroup = null; - - $cFDefaultGroup = $this->em->getRepository("ChillCustomFieldsBundle:CustomFieldsDefaultGroup") - ->findOneByEntity("Chill\PersonBundle\Entity\Person"); - - if($cFDefaultGroup) { - $cFGroup = $cFDefaultGroup->getCustomFieldsGroup(); - } - - return $cFGroup; } - public function viewAction($person_id) + public function createAction(Request $request) { - $person = $this->_getPerson($person_id); + if ($request->getMethod() !== 'POST') { + $r = new Response('You must send something to create a person !'); + $r->setStatusCode(400); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found on this server"); + return $r; } - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, - "You are not allowed to see this person."); + $form = $this->createForm(CreationPersonType::class, null, [ + 'form_status' => CreationPersonType::FORM_REVIEWED, + ]); - $event = new PrivacyEvent($person); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + $form->handleRequest($request); - return $this->render('ChillPersonBundle:Person:view.html.twig', - array( - "person" => $person, - "cFGroup" => $this->getCFGroup(), - "alt_names" => $this->configPersonAltNameHelper->getChoices(), + $person = $this->_bindCreationForm($form); + + $errors = $this->_validatePersonAndAccompanyingPeriod($person); + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_CREATE', + $person, + 'You are not allowed to create this person' + ); + + if ($errors->count() === 0) { + $this->em->persist($person); + + $this->em->flush(); + + return $this->redirect($this->generateUrl( + 'chill_person_general_edit', + ['person_id' => $person->getId()] )); + } + $text = "this should not happen if you reviewed your submission\n"; + + foreach ($errors as $error) { + $text .= $error->getMessage() . "\n"; + } + $r = new Response($text); + $r->setStatusCode(400); + + return $r; } public function editAction($person_id) { $person = $this->_getPerson($person_id); - if ($person === null) { + if (null === $person) { return $this->createNotFoundException(); } - $this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person, - 'You are not allowed to edit this person'); - - $form = $this->createForm(PersonType::class, $person, - array( - "action" => $this->generateUrl('chill_person_general_update', - array("person_id" => $person_id)), - "cFGroup" => $this->getCFGroup() - ) + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_UPDATE', + $person, + 'You are not allowed to edit this person' ); - return $this->render('ChillPersonBundle:Person:edit.html.twig', - array('person' => $person, 'form' => $form->createView())); + $form = $this->createForm( + PersonType::class, + $person, + [ + 'action' => $this->generateUrl( + 'chill_person_general_update', + ['person_id' => $person_id] + ), + 'cFGroup' => $this->getCFGroup(), + ] + ); + + return $this->render( + 'ChillPersonBundle:Person:edit.html.twig', + ['person' => $person, 'form' => $form->createView()] + ); } - public function updateAction($person_id, Request $request) + public function getCFGroup() { - $person = $this->_getPerson($person_id); + $cFGroup = null; - if ($person === null) { - return $this->createNotFoundException(); + $cFDefaultGroup = $this->em->getRepository('ChillCustomFieldsBundle:CustomFieldsDefaultGroup') + ->findOneByEntity('Chill\\PersonBundle\\Entity\\Person'); + + if ($cFDefaultGroup) { + $cFGroup = $cFDefaultGroup->getCustomFieldsGroup(); } - $this->denyAccessUnlessGranted('CHILL_PERSON_UPDATE', $person, - 'You are not allowed to edit this person'); - - $form = $this->createForm(PersonType::class, $person, - array("cFGroup" => $this->getCFGroup())); - - if ($request->getMethod() === 'POST') { - $form->handleRequest($request); - - if ( ! $form->isValid() ) { - $this->get('session') - ->getFlashBag()->add('error', $this->translator - ->trans('This form contains errors')); - - return $this->render('ChillPersonBundle:Person:edit.html.twig', - array('person' => $person, - 'form' => $form->createView())); - } - - $this->get('session')->getFlashBag() - ->add('success', - $this->get('translator') - ->trans('The person data has been updated') - ); - - $this->em->flush(); - - $url = $this->generateUrl('chill_person_view', array( - 'person_id' => $person->getId() - )); - - return $this->redirect($url); - } + return $cFGroup; } public function newAction() { // this is a dummy default center. $defaultCenter = $this->get('security.token_storage') - ->getToken() - ->getUser() - ->getGroupCenters()[0] - ->getCenter(); + ->getToken() + ->getUser() + ->getGroupCenters()[0] + ->getCenter(); - $person = (new Person(new \DateTime('now'))) - ->setCenter($defaultCenter); + $person = (new Person(new DateTime('now'))) + ->setCenter($defaultCenter); $form = $this->createForm( - CreationPersonType::class, - $person, - array( - 'action' => $this->generateUrl('chill_person_review'), - 'form_status' => CreationPersonType::FORM_NOT_REVIEWED - )); + CreationPersonType::class, + $person, + [ + 'action' => $this->generateUrl('chill_person_review'), + 'form_status' => CreationPersonType::FORM_NOT_REVIEWED, + ] + ); return $this->_renderNewForm($form); } - private function _renderNewForm($form) + public function reviewAction(Request $request) { - return $this->render('ChillPersonBundle:Person:create.html.twig', - array( - 'form' => $form->createView() - )); + if ($request->getMethod() !== 'POST') { + $r = new Response('You must send something to review the creation of a new Person'); + $r->setStatusCode(400); + + return $r; + } + + $form = $this->createForm( + //CreationPersonType::NAME, + CreationPersonType::class, + new Person(), + [ + 'action' => $this->generateUrl('chill_person_create'), + 'form_status' => CreationPersonType::FORM_BEING_REVIEWED, + ] + ); + + $form->handleRequest($request); + + $person = $this->_bindCreationForm($form); + + $errors = $this->_validatePersonAndAccompanyingPeriod($person); + $this->logger->info(sprintf('Person created with %d errors ', count($errors))); + + if ($errors->count() > 0) { + $this->logger->info('The created person has errors'); + $flashBag = $this->get('session')->getFlashBag(); + $translator = $this->get('translator'); + + $flashBag->add('error', $translator->trans('The person data are not valid')); + + foreach ($errors as $error) { + $flashBag->add('info', $error->getMessage()); + } + + $form = $this->createForm( + CreationPersonType::NAME, + $person, + [ + 'action' => $this->generateUrl('chill_person_review'), + 'form_status' => CreationPersonType::FORM_NOT_REVIEWED, + ] + ); + + $form->handleRequest($request); + + return $this->_renderNewForm($form); + } + $this->logger->info('Person created without errors'); + + $this->em->persist($person); + + $alternatePersons = $this->similarPersonMatcher + ->matchPerson($person); + + if (count($alternatePersons) === 0) { + return $this->forward('ChillPersonBundle:Person:create'); + } + + $this->get('session')->getFlashBag()->add( + 'info', + $this->get('translator')->trans( + '%nb% person with similar name. Please verify that this is a new person', + ['%nb%' => count($alternatePersons)] + ) + ); + + return $this->render( + 'ChillPersonBundle:Person:create_review.html.twig', + [ + 'person' => $person, + 'alternatePersons' => $alternatePersons, + 'firstName' => $form['firstName']->getData(), + 'lastName' => $form['lastName']->getData(), + 'birthdate' => $form['birthdate']->getData(), + 'gender' => $form['gender']->getData(), + 'creation_date' => $form['creation_date']->getData(), + 'form' => $form->createView(), ] + ); + } + + public function updateAction($person_id, Request $request) + { + $person = $this->_getPerson($person_id); + + if (null === $person) { + return $this->createNotFoundException(); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_UPDATE', + $person, + 'You are not allowed to edit this person' + ); + + $form = $this->createForm( + PersonType::class, + $person, + ['cFGroup' => $this->getCFGroup()] + ); + + if ($request->getMethod() === 'POST') { + $form->handleRequest($request); + + if (!$form->isValid()) { + $this->get('session') + ->getFlashBag()->add('error', $this->translator + ->trans('This form contains errors')); + + return $this->render( + 'ChillPersonBundle:Person:edit.html.twig', + ['person' => $person, + 'form' => $form->createView(), ] + ); + } + + $this->get('session')->getFlashBag() + ->add( + 'success', + $this->get('translator') + ->trans('The person data has been updated') + ); + + $this->em->flush(); + + $url = $this->generateUrl('chill_person_view', [ + 'person_id' => $person->getId(), + ]); + + return $this->redirect($url); + } + } + + public function viewAction($person_id) + { + $person = $this->_getPerson($person_id); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found on this server'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_SEE', + $person, + 'You are not allowed to see this person.' + ); + + $event = new PrivacyEvent($person); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render( + 'ChillPersonBundle:Person:view.html.twig', + [ + 'person' => $person, + 'cFGroup' => $this->getCFGroup(), + 'alt_names' => $this->configPersonAltNameHelper->getChoices(), + ] + ); } /** - * * @param type $form + * * @return \Chill\PersonBundle\Entity\Person */ private function _bindCreationForm($form) @@ -265,14 +395,34 @@ final class PersonController extends AbstractController } /** + * easy getting a person by his id. * - * @param \Chill\PersonBundle\Entity\Person $person + * @param mixed $id + * + * @return \Chill\PersonBundle\Entity\Person + */ + private function _getPerson($id) + { + return $this->personRepository->find($id); + } + + private function _renderNewForm($form) + { + return $this->render( + 'ChillPersonBundle:Person:create.html.twig', + [ + 'form' => $form->createView(), + ] + ); + } + + /** * @return \Symfony\Component\Validator\ConstraintViolationListInterface */ private function _validatePersonAndAccompanyingPeriod(Person $person) { $errors = $this->validator - ->validate($person, null, array('creation')); + ->validate($person, null, ['creation']); //validate accompanying periods $periods = $person->getAccompanyingPeriods(); @@ -282,139 +432,11 @@ final class PersonController extends AbstractController ->validate($period); //group errors : - foreach($period_errors as $error) { + foreach ($period_errors as $error) { $errors->add($error); } } return $errors; } - - public function reviewAction(Request $request) - { - if ($request->getMethod() !== 'POST') { - $r = new Response("You must send something to review the creation of a new Person"); - $r->setStatusCode(400); - return $r; - } - - $form = $this->createForm( - //CreationPersonType::NAME, - CreationPersonType::class, - new Person(), - array( - 'action' => $this->generateUrl('chill_person_create'), - 'form_status' => CreationPersonType::FORM_BEING_REVIEWED - )); - - $form->handleRequest($request); - - $person = $this->_bindCreationForm($form); - - $errors = $this->_validatePersonAndAccompanyingPeriod($person); - $this->logger->info(sprintf('Person created with %d errors ', count($errors))); - - if ($errors->count() > 0) { - $this->logger->info('The created person has errors'); - $flashBag = $this->get('session')->getFlashBag(); - $translator = $this->get('translator'); - - $flashBag->add('error', $translator->trans('The person data are not valid')); - - foreach($errors as $error) { - $flashBag->add('info', $error->getMessage()); - } - - $form = $this->createForm( - CreationPersonType::NAME, - $person, - array( - 'action' => $this->generateUrl('chill_person_review'), - 'form_status' => CreationPersonType::FORM_NOT_REVIEWED - )); - - $form->handleRequest($request); - - return $this->_renderNewForm($form); - } else { - $this->logger->info('Person created without errors'); - } - - $this->em->persist($person); - - $alternatePersons = $this->similarPersonMatcher - ->matchPerson($person); - - if (count($alternatePersons) === 0) { - return $this->forward('ChillPersonBundle:Person:create'); - } - - $this->get('session')->getFlashBag()->add('info', - $this->get('translator')->trans( - '%nb% person with similar name. Please verify that this is a new person', - array('%nb%' => count($alternatePersons))) - ); - - return $this->render('ChillPersonBundle:Person:create_review.html.twig', - array( - 'person' => $person, - 'alternatePersons' => $alternatePersons, - 'firstName' => $form['firstName']->getData(), - 'lastName' => $form['lastName']->getData(), - 'birthdate' => $form['birthdate']->getData(), - 'gender' => $form['gender']->getData(), - 'creation_date' => $form['creation_date']->getData(), - 'form' => $form->createView())); - } - - public function createAction(Request $request) - { - - if ($request->getMethod() !== 'POST') { - $r = new Response('You must send something to create a person !'); - $r->setStatusCode(400); - return $r; - } - - $form = $this->createForm(CreationPersonType::class, null, array( - 'form_status' => CreationPersonType::FORM_REVIEWED - )); - - $form->handleRequest($request); - - $person = $this->_bindCreationForm($form); - - $errors = $this->_validatePersonAndAccompanyingPeriod($person); - - $this->denyAccessUnlessGranted('CHILL_PERSON_CREATE', $person, - 'You are not allowed to create this person'); - - if ($errors->count() === 0) { - $this->em->persist($person); - - $this->em->flush(); - - return $this->redirect($this->generateUrl('chill_person_general_edit', - array('person_id' => $person->getId()))); - } else { - $text = "this should not happen if you reviewed your submission\n"; - foreach ($errors as $error) { - $text .= $error->getMessage()."\n"; - } - $r = new Response($text); - $r->setStatusCode(400); - return $r; - } - } - - /** - * easy getting a person by his id - * @return \Chill\PersonBundle\Entity\Person - */ - private function _getPerson($id) - { - $person = $this->personRepository->find($id); - - return $person; - } } diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php index aa2e2768a..dac98fe8b 100644 --- a/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php +++ b/src/Bundle/ChillPersonBundle/Controller/PersonDuplicateController.php @@ -1,9 +1,18 @@ similarPersonMatcher = $similarPersonMatcher; $this->translator = $translator; @@ -62,30 +68,6 @@ class PersonDuplicateController extends Controller $this->eventDispatcher = $eventDispatcher; } - public function viewAction($person_id) - { - $person = $this->_getPerson($person_id); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found on this server"); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person, - "You are not allowed to see this person."); - - $duplicatePersons = $this->similarPersonMatcher-> - matchPerson($person, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL); - - $notDuplicatePersons = $this->getDoctrine()->getRepository(PersonNotDuplicate::class) - ->findNotDuplicatePerson($person); - - return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [ - 'person' => $person, - 'duplicatePersons' => $duplicatePersons, - 'notDuplicatePersons' => $notDuplicatePersons, - ]); - } - public function confirmAction($person1_id, $person2_id, Request $request) { if ($person1_id === $person2_id) { @@ -97,18 +79,21 @@ class PersonDuplicateController extends Controller $person1->counters = $this->_getCounters($person1_id); $person2->counters = $this->_getCounters($person2_id); - - if ($person1 === null) { - throw $this->createNotFoundException("Person with id $person1_id not" - . " found on this server"); + + if (null === $person1) { + throw $this->createNotFoundException("Person with id {$person1_id} not" + . ' found on this server'); } - $this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1, - "You are not allowed to see this person."); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DUPLICATE', + $person1, + 'You are not allowed to see this person.' + ); - if ($person2 === null) { - throw $this->createNotFoundException("Person with id $person2_id not" - . " found on this server"); + if (null === $person2) { + throw $this->createNotFoundException("Person with id {$person2_id} not" + . ' found on this server'); } $form = $this->createForm(PersonConfimDuplicateType::class); @@ -116,10 +101,10 @@ class PersonDuplicateController extends Controller $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $event = new PrivacyEvent($person1, array( + $event = new PrivacyEvent($person1, [ 'element_class' => Person::class, - 'action' => 'move' - )); + 'action' => 'move', + ]); $event->addPerson($person2); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); @@ -128,7 +113,8 @@ class PersonDuplicateController extends Controller $connection = $this->getDoctrine()->getConnection(); $connection->beginTransaction(); - foreach($sqls as $sql) { + + foreach ($sqls as $sql) { $connection->executeQuery($sql); } $connection->commit(); @@ -143,15 +129,68 @@ class PersonDuplicateController extends Controller ]); } + public function findManuallyDuplicateAction($person_id, Request $request) + { + $person = $this->_getPerson($person_id); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found on this server'); + } + + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DUPLICATE', + $person, + 'You are not allowed to see this person.' + ); + + $form = $this->createForm(PersonFindManuallyDuplicateType::class); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $person2 = $form->get('person')->getData(); + + if (null === $person2) { + throw $this->createNotFoundException("Person with id {$person2->getId}() not" + . ' found on this server'); + } + + $direction = $form->get('direction')->getData(); + + if ('starting' === $direction) { + $params = [ + 'person1_id' => $person->getId(), + 'person2_id' => $person2->getId(), + ]; + } else { + $params = [ + 'person1_id' => $person2->getId(), + 'person2_id' => $person->getId(), + ]; + } + + return $this->redirectToRoute('chill_person_duplicate_confirm', $params); + } + + return $this->render('ChillPersonBundle:PersonDuplicate:find_manually.html.twig', [ + 'person' => $person, + 'form' => $form->createView(), + ]); + } + public function notDuplicateAction($person1_id, $person2_id) { [$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id); - $this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1, - "You are not allowed to see this person."); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DUPLICATE', + $person1, + 'You are not allowed to see this person.' + ); $personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class) - ->findOneBy(['person1' => $person1, 'person2' => $person2]); + ->findOneBy(['person1' => $person1, 'person2' => $person2]); if (!$personNotDuplicate instanceof PersonNotDuplicate) { $personNotDuplicate = new PersonNotDuplicate(); @@ -170,11 +209,14 @@ class PersonDuplicateController extends Controller { [$person1, $person2] = $this->_getPersonsByPriority($person1_id, $person2_id); - $this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person1, - "You are not allowed to see this person."); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DUPLICATE', + $person1, + 'You are not allowed to see this person.' + ); $personNotDuplicate = $this->getDoctrine()->getRepository(PersonNotDuplicate::class) - ->findOneBy(['person1' => $person1, 'person2' => $person2]); + ->findOneBy(['person1' => $person1, 'person2' => $person2]); if ($personNotDuplicate instanceof PersonNotDuplicate) { $this->getDoctrine()->getManager()->remove($personNotDuplicate); @@ -184,54 +226,57 @@ class PersonDuplicateController extends Controller return $this->redirectToRoute('chill_person_duplicate_view', ['person_id' => $person1->getId()]); } - public function findManuallyDuplicateAction($person_id, Request $request) + public function viewAction($person_id) { $person = $this->_getPerson($person_id); - if ($person === null) { - throw $this->createNotFoundException("Person with id $person_id not" - . " found on this server"); + + if (null === $person) { + throw $this->createNotFoundException("Person with id {$person_id} not" + . ' found on this server'); } - $this->denyAccessUnlessGranted('CHILL_PERSON_DUPLICATE', $person, - "You are not allowed to see this person."); + $this->denyAccessUnlessGranted( + 'CHILL_PERSON_DUPLICATE', + $person, + 'You are not allowed to see this person.' + ); - $form = $this->createForm(PersonFindManuallyDuplicateType::class); + $duplicatePersons = $this->similarPersonMatcher-> + matchPerson($person, 0.5, SimilarPersonMatcher::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL); - $form->handleRequest($request); + $notDuplicatePersons = $this->getDoctrine()->getRepository(PersonNotDuplicate::class) + ->findNotDuplicatePerson($person); - if ($form->isSubmitted() && $form->isValid()) { - $person2 = $form->get('person')->getData(); - - if ($person2 === null) { - throw $this->createNotFoundException("Person with id $person2->getId() not" - . " found on this server"); - } - - $direction = $form->get('direction')->getData(); - - if ($direction === 'starting') { - $params = [ - 'person1_id' => $person->getId(), - 'person2_id' => $person2->getId(), - ]; - } else { - $params = [ - 'person1_id' => $person2->getId(), - 'person2_id' => $person->getId(), - ]; - } - - return $this->redirectToRoute('chill_person_duplicate_confirm', $params); - } - - return $this->render('ChillPersonBundle:PersonDuplicate:find_manually.html.twig', [ + return $this->render('ChillPersonBundle:PersonDuplicate:view.html.twig', [ 'person' => $person, - 'form' => $form->createView(), + 'duplicatePersons' => $duplicatePersons, + 'notDuplicatePersons' => $notDuplicatePersons, ]); } + private function _getCounters($id): ?array + { + $em = $this->getDoctrine()->getManager(); + + $nb_activity = $em->getRepository(Activity::class)->findBy(['person' => $id]); + $nb_document = $em->getRepository(PersonDocument::class)->findBy(['person' => $id]); + $nb_event = $em->getRepository(Participation::class)->findBy(['person' => $id]); + $nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person' => $id]); + $person = $em->getRepository(Person::class)->findOneBy(['id' => $id]); + + return [ + 'nb_activity' => count($nb_activity), + 'nb_document' => count($nb_document), + 'nb_event' => count($nb_event), + 'nb_task' => $nb_task, + 'nb_addresses' => count($person->getAddresses()), + ]; + } + /** - * easy getting a person by his id + * easy getting a person by his id. + * + * @param mixed $id */ private function _getPerson($id): ?Person { @@ -252,35 +297,16 @@ class PersonDuplicateController extends Controller $person2 = $this->_getPerson($person2_id); } - if ($person1 === null) { - throw $this->createNotFoundException("Person with id $person1_id not" - . " found on this server"); + if (null === $person1) { + throw $this->createNotFoundException("Person with id {$person1_id} not" + . ' found on this server'); } - if ($person2 === null) { - throw $this->createNotFoundException("Person with id $person2_id not" - . " found on this server"); + if (null === $person2) { + throw $this->createNotFoundException("Person with id {$person2_id} not" + . ' found on this server'); } return [$person1, $person2]; } - - private function _getCounters($id): ?array - { - $em = $this->getDoctrine()->getManager(); - - $nb_activity = $em->getRepository(Activity::class)->findBy(['person'=>$id]); - $nb_document = $em->getRepository(PersonDocument::class)->findBy(['person'=>$id]); - $nb_event = $em->getRepository(Participation::class)->findBy(['person'=>$id]); - $nb_task = $em->getRepository(SingleTask::class)->countByParameters(['person'=>$id]); - $person = $em->getRepository(Person::class)->findOneBy(['id'=>$id]); - - return [ - 'nb_activity' => count($nb_activity), - 'nb_document' => count($nb_document), - 'nb_event' => count($nb_event), - 'nb_task' => $nb_task, - 'nb_addresses' => count($person->getAddresses()) - ]; - } } diff --git a/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php b/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php index 774351581..e306ce82a 100644 --- a/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php +++ b/src/Bundle/ChillPersonBundle/Controller/TimelinePersonController.php @@ -1,63 +1,44 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Controller; +use Chill\MainBundle\Pagination\PaginatorFactory; +use Chill\MainBundle\Timeline\TimelineBuilder; use Chill\PersonBundle\Privacy\PrivacyEvent; +use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; -use Chill\MainBundle\Timeline\TimelineBuilder; -use Chill\MainBundle\Pagination\PaginatorFactory; -use Chill\PersonBundle\Security\Authorization\PersonVoter; /** - * Class TimelinePersonController - * - * @package Chill\PersonBundle\Controller - * @author Julien Fastré + * Class TimelinePersonController. */ class TimelinePersonController extends AbstractController { - /** * @var EventDispatcherInterface */ protected $eventDispatcher; - + /** - * - * @var TimelineBuilder - */ - protected $timelineBuilder; - - /** - * * @var PaginatorFactory */ protected $paginatorFactory; - + + /** + * @var TimelineBuilder + */ + protected $timelineBuilder; + /** * TimelinePersonController constructor. - * - * @param EventDispatcherInterface $eventDispatcher */ public function __construct( EventDispatcherInterface $eventDispatcher, @@ -68,42 +49,42 @@ class TimelinePersonController extends AbstractController $this->timelineBuilder = $timelineBuilder; $this->paginatorFactory = $paginatorFactory; } - - + public function personAction(Request $request, $person_id) { $person = $this->getDoctrine() - ->getRepository('ChillPersonBundle:Person') - ->find($person_id); + ->getRepository('ChillPersonBundle:Person') + ->find($person_id); - if ($person === NULL) { + if (null === $person) { throw $this->createNotFoundException(); } - + $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); - - $nbItems = $this->timelineBuilder->countItems('person', - [ 'person' => $person ] - ); - + + $nbItems = $this->timelineBuilder->countItems( + 'person', + ['person' => $person] + ); + $paginator = $this->paginatorFactory->create($nbItems); - - $event = new PrivacyEvent($person, array('action' => 'timeline')); + + $event = new PrivacyEvent($person, ['action' => 'timeline']); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillPersonBundle:Timeline:index.html.twig', array - ( + + return $this->render( + 'ChillPersonBundle:Timeline:index.html.twig', + [ 'timeline' => $this->timelineBuilder->getTimelineHTML( - 'person', - array('person' => $person), + 'person', + ['person' => $person], $paginator->getCurrentPage()->getFirstItemNumber(), $paginator->getItemsPerPage() - ), + ), 'person' => $person, 'nb_items' => $nbItems, - 'paginator' => $paginator - ) + 'paginator' => $paginator, + ] ); } - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriod.php index a30943bcb..2f0e13a42 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriod.php @@ -1,57 +1,40 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; +use DateTime; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; - /** - * Description of LoadAccompanyingPeriod - * - * @author Champs-Libres Coop + * Description of LoadAccompanyingPeriod. */ class LoadAccompanyingPeriod extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - public const ACCOMPANYING_PERIOD = 'parcours 1'; + public static $references = []; + public function getOrder() { return 10004; } - public static $references = array(); - public function load(ObjectManager $manager) { - $centerA = $this->getReference('centerA'); $centerAId = $centerA->getId(); @@ -65,7 +48,7 @@ class LoadAccompanyingPeriod extends AbstractFixture implements OrderedFixtureIn ->getQuery() ->getScalarResult(); - $openingDate = new \DateTime('2020-04-01'); + $openingDate = new DateTime('2020-04-01'); $person1 = $manager->getRepository(Person::class)->find($personIds[0]); $person2 = $manager->getRepository(Person::class)->find($personIds[1]); diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodClosingMotive.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodClosingMotive.php index fad0596a6..e105e15e7 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodClosingMotive.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodClosingMotive.php @@ -1,89 +1,68 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; /** - * Load closing motives into database - * - * @author Julien Fastré + * Load closing motives into database. */ -class LoadAccompanyingPeriodClosingMotive extends AbstractFixture - implements OrderedFixtureInterface +class LoadAccompanyingPeriodClosingMotive extends AbstractFixture implements OrderedFixtureInterface { - - public function getOrder() { + public static $closingMotives = [ + 'nothing_to_do' => [ + 'name' => [ + 'fr' => 'Plus rien à faire', + 'en' => 'Nothing to do', + 'nl' => 'nieks meer te doen', + ], + ], + 'did_not_come_back' => [ + 'name' => [ + 'fr' => "N'est plus revenu", + 'en' => "Did'nt come back", + 'nl' => 'Niet teruggekomen', + ], + ], + 'no_more_money' => [ + 'active' => false, + 'name' => [ + 'fr' => "Plus d'argent", + 'en' => 'No more money', + 'nl' => 'Geen geld', + ], + ], + ]; + + public static $references = []; + + public function getOrder() + { return 9500; } - - public static $closingMotives = array( - 'nothing_to_do' => array( - 'name' => array( - 'fr' => 'Plus rien à faire', - 'en' => 'Nothing to do', - 'nl' => 'nieks meer te doen' - ) - ), - 'did_not_come_back' => array( - 'name' => array( - 'fr' => "N'est plus revenu", - 'en' => "Did'nt come back", - 'nl' => "Niet teruggekomen" - ) - ), - 'no_more_money' => array( - 'active' => false, - 'name' => array( - 'fr' => "Plus d'argent", - 'en' => "No more money", - 'nl' => "Geen geld" - ) - ) - ); - - public static $references = array(); - - public function load(ObjectManager $manager) + + public function load(ObjectManager $manager) { foreach (static::$closingMotives as $ref => $new) { $motive = new ClosingMotive(); $motive->setName($new['name']) - ->setActive((isset($new['active']) ? $new['active'] : true)) - ; - + ->setActive(($new['active'] ?? true)); + $manager->persist($motive); $this->addReference($ref, $motive); - echo "Adding ClosingMotive $ref\n"; + echo "Adding ClosingMotive {$ref}\n"; } - + $manager->flush(); } - - - - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php index cbec9c439..b5099700a 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadAccompanyingPeriodOrigin.php @@ -1,52 +1,35 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin; - /** - * Description of LoadAccompanyingPeriodOrigin - * - * @author Champs-Libres Coop + * Description of LoadAccompanyingPeriodOrigin. */ class LoadAccompanyingPeriodOrigin extends AbstractFixture implements OrderedFixtureInterface { - public const ACCOMPANYING_PERIOD_ORIGIN = 'accompanying_period_origin'; + public static $references = []; + + private $phoneCall = ['en' => 'phone call', 'fr' => 'appel téléphonique']; + public function getOrder() { return 10005; } - private $phoneCall = ['en' => 'phone call', 'fr' => 'appel téléphonique']; - - public static $references = array(); - public function load(ObjectManager $manager) { $o = new Origin(); diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php index 235cadd95..2fdaa0aa3 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadCustomFields.php @@ -1,78 +1,61 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice; +use Chill\CustomFieldsBundle\CustomFields\CustomFieldText; +use Chill\CustomFieldsBundle\CustomFields\CustomFieldTitle; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Entity\CustomFieldsDefaultGroup; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Entity\Person; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; +use RuntimeException; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldTitle; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldText; -use Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice; -use Chill\CustomFieldsBundle\Entity\CustomFieldsDefaultGroup; -use Chill\PersonBundle\Entity\Person; use Symfony\Contracts\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ -class LoadCustomFields extends AbstractFixture implements OrderedFixtureInterface, - ContainerAwareInterface +class LoadCustomFields extends AbstractFixture implements + OrderedFixtureInterface, + ContainerAwareInterface { /** - * * @var ContainerInterface */ private $container; - + /** - * - * @var CustomField - */ - private $customFieldText; - - /** - * * @var CustomField */ private $customFieldChoice; - + + /** + * @var CustomField + */ + private $customFieldText; + /** * @var TranslatableStringHelper */ private $translatableStringHelper; - + /** * @var TranslatorInterface */ private $translator; - + /** * LoadCustomFields constructor. - * - * @param TranslatableStringHelper $translatableStringHelper - * @param TranslatorInterface $translator */ public function __construct( TranslatableStringHelper $translatableStringHelper, @@ -81,21 +64,12 @@ class LoadCustomFields extends AbstractFixture implements OrderedFixtureInterfac $this->translatableStringHelper = $translatableStringHelper; $this->translator = $translator; } - + //put your code here public function getOrder() { return 10003; } - - public function setContainer(ContainerInterface $container = null) - { - if ($container === null) { - throw new \RuntimeException("The given container should not be null"); - } - - $this->container = $container; - } public function load(ObjectManager $manager) { @@ -103,45 +77,16 @@ class LoadCustomFields extends AbstractFixture implements OrderedFixtureInterfac $this->loadData($manager); $manager->flush(); } - - private function loadData(ObjectManager $manager) + + public function setContainer(?ContainerInterface $container = null) { - $personIds = $this->container->get('doctrine.orm.entity_manager') - ->createQuery("SELECT person.id FROM ChillPersonBundle:Person person") - ->getScalarResult(); - - // get possible values for cfGroup - $choices = array_map( - function($a) { return $a["slug"]; }, - $this->customFieldChoice->getOptions()["choices"] - ); - // create faker - $faker = \Faker\Factory::create('fr_FR'); - // select a set of people and add data - foreach ($personIds as $id) { - // add info on 1 person on 2 - if (rand(0,1) === 1) { - /* @var $person Person */ - $person = $manager->getRepository(Person::class)->find($id); - $person->setCFData(array( - "remarques" => $this->createCustomFieldText() - ->serialize($faker->text(rand(150, 250)), $this->customFieldText), - "document-d-identite" => $this->createCustomFieldChoice() - ->serialize(array($choices[array_rand($choices)]), $this->customFieldChoice) - )); - } + if (null === $container) { + throw new RuntimeException('The given container should not be null'); } + + $this->container = $container; } - - private function createCustomFieldText() - { - return new CustomFieldText( - $this->container->get('request_stack'), - $this->container->get('templating'), - $this->translatableStringHelper - ); - } - + private function createCustomFieldChoice() { return new CustomFieldChoice( @@ -150,80 +95,115 @@ class LoadCustomFields extends AbstractFixture implements OrderedFixtureInterfac $this->translatableStringHelper ); } - + + private function createCustomFieldText() + { + return new CustomFieldText( + $this->container->get('request_stack'), + $this->container->get('templating'), + $this->translatableStringHelper + ); + } + + private function loadData(ObjectManager $manager) + { + $personIds = $this->container->get('doctrine.orm.entity_manager') + ->createQuery('SELECT person.id FROM ChillPersonBundle:Person person') + ->getScalarResult(); + + // get possible values for cfGroup + $choices = array_map( + function ($a) { + return $a['slug']; + }, + $this->customFieldChoice->getOptions()['choices'] + ); + // create faker + $faker = \Faker\Factory::create('fr_FR'); + // select a set of people and add data + foreach ($personIds as $id) { + // add info on 1 person on 2 + if (rand(0, 1) === 1) { + /* @var $person Person */ + $person = $manager->getRepository(Person::class)->find($id); + $person->setCFData([ + 'remarques' => $this->createCustomFieldText() + ->serialize($faker->text(rand(150, 250)), $this->customFieldText), + 'document-d-identite' => $this->createCustomFieldChoice() + ->serialize([$choices[array_rand($choices)]], $this->customFieldChoice), + ]); + } + } + } + private function loadFields(ObjectManager $manager) { $cfGroup = (new CustomFieldsGroup()) ->setEntity(Person::class) - ->setName(array("fr" => "Données")) - ; + ->setName(['fr' => 'Données']); $manager->persist($cfGroup); - + // make this group default for Person::class $manager->persist( (new CustomFieldsDefaultGroup()) ->setCustomFieldsGroup($cfGroup) ->setEntity(Person::class) - ); - + ); + // create title field $customField0 = (new CustomField()) ->setActive(true) - ->setName(array("fr" => "Données personnalisées")) - ->setSlug("personal-data") + ->setName(['fr' => 'Données personnalisées']) + ->setSlug('personal-data') ->setOrdering(10) ->setType('title') - ->setOptions(array(CustomFieldTitle::TYPE => CustomFieldTitle::TYPE_TITLE)) - ->setCustomFieldsGroup($cfGroup) - ; + ->setOptions([CustomFieldTitle::TYPE => CustomFieldTitle::TYPE_TITLE]) + ->setCustomFieldsGroup($cfGroup); $manager->persist($customField0); - + // create text field $this->customFieldText = (new CustomField()) ->setActive(true) - ->setName(array("fr" => "Remarques")) - ->setSlug("remarques") + ->setName(['fr' => 'Remarques']) + ->setSlug('remarques') ->setOrdering(20) ->setType('text') - ->setOptions(array('maxLength' => 5000)) - ->setCustomFieldsGroup($cfGroup) - ; + ->setOptions(['maxLength' => 5000]) + ->setCustomFieldsGroup($cfGroup); $manager->persist($this->customFieldText); - + // create choice field $this->customFieldChoice = (new CustomField()) ->setActive(true) - ->setName(array("fr" => "Document d'identité")) - ->setSlug("document-d-identite") + ->setName(['fr' => "Document d'identité"]) + ->setSlug('document-d-identite') ->setOrdering(30) ->setType('choice') ->setCustomFieldsGroup($cfGroup) - ->setOptions(array( - "multiple" => true, - "other" => false, - "expanded" => true, - "active" => true, - "slug" => "document-d-identite", - "choices" => array( - array( - "name" => array("fr" => "Carte d'identité"), - "active" => true, - "slug" => "carte-d-identite" - ), - array( - "name" => array("fr" => "Passeport"), - "active" => true, - "slug" => "passeport" - ), - array( - "name" => array("fr" => "Titre de séjour"), - "active" => true, - "slug" => "passeport" - ) - ) - )) - ; + ->setOptions([ + 'multiple' => true, + 'other' => false, + 'expanded' => true, + 'active' => true, + 'slug' => 'document-d-identite', + 'choices' => [ + [ + 'name' => ['fr' => "Carte d'identité"], + 'active' => true, + 'slug' => 'carte-d-identite', + ], + [ + 'name' => ['fr' => 'Passeport'], + 'active' => true, + 'slug' => 'passeport', + ], + [ + 'name' => ['fr' => 'Titre de séjour'], + 'active' => true, + 'slug' => 'passeport', + ], + ], + ]); $manager->persist($this->customFieldChoice); } - } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadMaritalStatus.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadMaritalStatus.php index b0cf57637..65d428436 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadMaritalStatus.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadMaritalStatus.php @@ -1,66 +1,52 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\PersonBundle\Entity\MaritalStatus; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\Entity\MaritalStatus; /** - * Load marital status into database - * - * @author Marc Ducobu + * Load marital status into database. */ class LoadMaritalStatus extends AbstractFixture implements OrderedFixtureInterface { private $maritalStatuses = [ - ['id' => 'single', 'name' =>['en' => 'single', 'fr' => 'célibataire']], - ['id' => 'married', 'name' =>['en' => 'married', 'fr' => 'marié(e)']], - ['id' => 'widow', 'name' =>['en' => 'widow', 'fr' => 'veuf – veuve ']], - ['id' => 'separat', 'name' =>['en' => 'separated', 'fr' => 'séparé(e)']], - ['id' => 'divorce', 'name' =>['en' => 'divorced', 'fr' => 'divorcé(e)']], - ['id' => 'legalco', 'name' =>['en' => 'legal cohabitant', 'fr' => 'cohabitant(e) légal(e)']], - ['id' => 'unknown', 'name' =>['en' => 'unknown', 'fr' => 'indéterminé']] + ['id' => 'single', 'name' => ['en' => 'single', 'fr' => 'célibataire']], + ['id' => 'married', 'name' => ['en' => 'married', 'fr' => 'marié(e)']], + ['id' => 'widow', 'name' => ['en' => 'widow', 'fr' => 'veuf – veuve ']], + ['id' => 'separat', 'name' => ['en' => 'separated', 'fr' => 'séparé(e)']], + ['id' => 'divorce', 'name' => ['en' => 'divorced', 'fr' => 'divorcé(e)']], + ['id' => 'legalco', 'name' => ['en' => 'legal cohabitant', 'fr' => 'cohabitant(e) légal(e)']], + ['id' => 'unknown', 'name' => ['en' => 'unknown', 'fr' => 'indéterminé']], ]; public function getOrder() { return 9999; } - + public function load(ObjectManager $manager) { echo "loading maritalStatuses... \n"; foreach ($this->maritalStatuses as $ms) { - echo $ms['name']['en'].' '; + echo $ms['name']['en'] . ' '; $new_ms = new MaritalStatus(); $new_ms->setId($ms['id']); $new_ms->setName($ms['name']); - $this->addReference('ms_'.$ms['id'], $new_ms); + $this->addReference('ms_' . $ms['id'], $new_ms); $manager->persist($new_ms); } - + $manager->flush(); } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php index e8697ff28..bec5567b4 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPeople.php @@ -1,76 +1,148 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; +use Chill\MainBundle\Doctrine\Model\Point; +use Chill\MainBundle\Entity\Address; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; +use DateTime; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\PersonBundle\Entity\Person; +use Exception; use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Chill\MainBundle\DataFixtures\ORM\LoadPostalCodes; -use Chill\MainBundle\Entity\Address; -use Chill\MainBundle\Doctrine\Model\Point; /** - * Load people into database - * - * @author Julien Fastré - * @author Marc Ducobu + * Load people into database. */ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { - use \Symfony\Component\DependencyInjection\ContainerAwareTrait; protected $faker; + private $day = []; + + private $firstNamesFemale = ['Svedana', 'Sevlatina', 'Irène', 'Marcelle', + 'Corentine', 'Alfonsine', 'Caroline', 'Solange', 'Gostine', 'Fatoumata', 'Nicole', + 'Groseille', 'Chana', 'Oxana', 'Ivana', 'Julie', 'Tina', 'Adèle', ]; + + private $firstNamesMale = ['Jean', 'Mohamed', 'Alfred', 'Robert', 'Justin', 'Brian', + 'Compère', 'Jean-de-Dieu', 'Charles', 'Pierre', 'Luc', 'Mathieu', 'Alain', 'Etienne', 'Eric', + 'Corentin', 'Gaston', 'Spirou', 'Fantasio', 'Mahmadou', 'Mohamidou', 'Vursuv', 'Youssef', ]; + + private $genders = [Person::MALE_GENDER, Person::FEMALE_GENDER]; + + private $lastNames = ['Diallo', 'Bah', 'Gaillot', 'Martin']; + + private $lastNamesTrigrams = ['fas', 'tré', 'hu', 'blart', 'van', 'der', 'lin', 'den', + 'ta', 'mi', 'net', 'gna', 'bol', 'sac', 'ré', 'jo', 'du', 'pont', 'cas', 'tor', 'rob', 'al', + 'ma', 'gone', 'car', 'fu', 'ka', 'lot', 'no', 'va', 'du', 'bu', 'su', 'jau', 'tte', 'sir', + 'lo', 'to', 'cho', 'car', 'mo', 'zu', 'qi', 'mu', ]; + + private $maritalStatusRef = ['ms_single', 'ms_married', 'ms_widow', 'ms_separat', + 'ms_divorce', 'ms_legalco', 'ms_unknown', ]; + + private $month = []; + + private $peoples = [ + [ + 'LastName' => 'Depardieu', + 'FirstName' => 'Gérard', + 'Birthdate' => '1948-12-27', + 'PlaceOfBirth' => 'Châteauroux', + 'Gender' => Person::MALE_GENDER, + 'CountryOfBirth' => 'FR', + 'Nationality' => 'RU', + 'center' => 'centerA', + 'maritalStatus' => 'ms_divorce', + 'accompanyingPeriods' => [ + [ + 'from' => '2015-02-01', + 'to' => '2015-10-30', + 'remark' => 'oops', + ], [ + 'from' => '2017-06-01', + 'to' => '2018-03-30', + 'remark' => 'argg', + ], [ + 'from' => '2019-01-01', + 'to' => '2019-12-31', + 'remark' => 'blob', + ], + ], + ], + [ + //to have a person with same firstname as Gérard Depardieu + 'LastName' => 'Depardieu', + 'FirstName' => 'Jean', + 'Birthdate' => '1960-10-12', + 'CountryOfBirth' => 'FR', + 'Nationality' => 'FR', + 'center' => 'centerA', + 'maritalStatus' => 'ms_divorce', + ], + [ + //to have a person with same birthdate of Gérard Depardieu + 'LastName' => 'Van Snick', + 'FirstName' => 'Bart', + 'Birthdate' => '1948-12-27', + 'center' => 'centerA', + 'maritalStatus' => 'ms_legalco', + ], + [ + //to have a woman with Depardieu as FirstName + 'LastName' => 'Depardieu', + 'FirstName' => 'Charline', + 'Gender' => Person::FEMALE_GENDER, + 'center' => 'centerA', + 'maritalStatus' => 'ms_legalco', + ], + [ + //to have a special character in lastName + 'LastName' => 'Manço', + 'FirstName' => 'Étienne', + 'center' => 'centerA', + 'maritalStatus' => 'ms_unknown', + ], + [ + //to have true duplicate person + 'LastName' => 'Depardieu', + 'FirstName' => 'Jean', + 'Birthdate' => '1960-10-12', + 'CountryOfBirth' => 'FR', + 'Nationality' => 'FR', + 'center' => 'centerA', + 'maritalStatus' => 'ms_divorce', + ], + [ + //to have false duplicate person + 'LastName' => 'Depardieu', + 'FirstName' => 'Jeanne', + 'Birthdate' => '1966-11-13', + 'CountryOfBirth' => 'FR', + 'Nationality' => 'FR', + 'center' => 'centerA', + 'maritalStatus' => 'ms_legalco', + ], + ]; + + private $years = []; + public function __construct() { $this->faker = \Faker\Factory::create('fr_FR'); } - public function prepare() - { - //prepare days, month, years - $y = 1950; - do { - $this->years[] = $y; - $y = $y +1; - } while ($y >= 1990); - - $m = 1; - do { - $this->month[] = $m; - $m = $m +1; - } while ($m >= 12); - - $d = 1; - do { - $this->day[] = $d; - $d = $d + 1; - } while ($d <= 28); - } - public function getOrder() { return 10000; @@ -99,19 +171,20 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $this->prepare(); - $chooseLastNameOrTri = array('tri', 'tri', 'name', 'tri'); + $chooseLastNameOrTri = ['tri', 'tri', 'name', 'tri']; $i = 0; do { - $i++; + ++$i; $sex = $this->genders[array_rand($this->genders)]; - if ($chooseLastNameOrTri[array_rand($chooseLastNameOrTri)] === 'tri' ) { + if ('tri' === $chooseLastNameOrTri[array_rand($chooseLastNameOrTri)]) { $length = rand(2, 3); $lastName = ''; - for ($j = 0; $j <= $length; $j++) { + + for ($j = 0; $j <= $length; ++$j) { $lastName .= $this->lastNamesTrigrams[array_rand($this->lastNamesTrigrams)]; } $lastName = ucfirst($lastName); @@ -119,66 +192,84 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $lastName = $this->lastNames[array_rand($this->lastNames)]; } - if ($sex === Person::MALE_GENDER) { + if (Person::MALE_GENDER === $sex) { $firstName = $this->firstNamesMale[array_rand($this->firstNamesMale)]; } else { $firstName = $this->firstNamesFemale[array_rand($this->firstNamesFemale)]; } // add an address on 80% of the created people - if (rand(0,100) < 80) { + if (rand(0, 100) < 80) { $address = $this->getRandomAddress(); // on 30% of those person, add multiple addresses - if (rand(0,10) < 4) { - $address = array( - $address, - $this->getRandomAddress() - ); + if (rand(0, 10) < 4) { + $address = [ + $address, + $this->getRandomAddress(), + ]; } } else { $address = null; } - $person = array( + $person = [ 'FirstName' => $firstName, 'LastName' => $lastName, 'Gender' => $sex, - 'Nationality' => (rand(0,100) > 50) ? NULL: 'BE', - 'center' => (rand(0,1) == 0) ? 'centerA': 'centerB', + 'Nationality' => (rand(0, 100) > 50) ? null : 'BE', + 'center' => (rand(0, 1) == 0) ? 'centerA' : 'centerB', 'Address' => $address, - 'maritalStatus' => $this->maritalStatusRef[array_rand($this->maritalStatusRef)] - ); + 'maritalStatus' => $this->maritalStatusRef[array_rand($this->maritalStatusRef)], + ]; $this->addAPerson($this->fillWithDefault($person), $manager); - - } while ($i <= 100); + } while (100 >= $i); } - /** - * fill a person array with default value - * - * @param string[] $specific - */ - private function fillWithDefault(array $specific) + public function prepare() { - return array_merge(array( - 'Birthdate' => "1960-10-12", - 'PlaceOfBirth' => "Ottignies Louvain-La-Neuve", - 'Gender' => Person::MALE_GENDER, - 'Email' => "Email d'un ami: roger@tt.com", - 'CountryOfBirth' => 'BE', - 'Nationality' => 'BE', - 'CFData' => array(), - 'Address' => null - ), $specific); + //prepare days, month, years + $y = 1950; + + do { + $this->years[] = $y; + $y = $y + 1; + } while (1990 <= $y); + + $m = 1; + + do { + $this->month[] = $m; + $m = $m + 1; + } while (12 <= $m); + + $d = 1; + + do { + $this->day[] = $d; + $d = $d + 1; + } while (28 >= $d); + } + + private function addAccompanyingPeriods(Person $person, array $periods, ObjectManager $manager) + { + foreach ($periods as $period) { + echo "adding new past Accompanying Period..\n"; + + /** @var AccompanyingPeriod $accompanyingPeriod */ + $accompanyingPeriod = new AccompanyingPeriod(new DateTime($period['from'])); + $accompanyingPeriod + ->setClosingDate(new DateTime($period['to'])) + ->setRemark($period['remark']); + + $person->addAccompanyingPeriod($accompanyingPeriod); + } } /** - * create a new person from array data + * create a new person from array data. * - * @param array $person - * @param ObjectManager $manager - * @throws \Exception + * @throws Exception */ private function addAPerson(array $person, ObjectManager $manager) { @@ -189,47 +280,103 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con case 'CountryOfBirth': case 'Nationality': $value = $this->getCountry($value); + break; + case 'Birthdate': - $value = new \DateTime($value); + $value = new DateTime($value); + break; + case 'center': case 'maritalStatus': $value = $this->getReference($value); + break; + case 'accompanyingPeriods': $this->addAccompanyingPeriods($p, $value, $manager); + break; } //try to add the data using the setSomething function, // if not possible, fallback to addSomething function - if (method_exists($p, 'set'.$key)) { - call_user_func(array($p, 'set'.$key), $value); - } elseif (method_exists($p, 'add'.$key)) { + if (method_exists($p, 'set' . $key)) { + call_user_func([$p, 'set' . $key], $value); + } elseif (method_exists($p, 'add' . $key)) { // if we have a "addSomething", we may have multiple items to add // so, we set the value in an array if it is not an array, and // will call the function addSomething multiple times if (!is_array($value)) { - $value = array($value); + $value = [$value]; } - foreach($value as $v) { - if ($v !== NULL) { - call_user_func(array($p, 'add'.$key), $v); + foreach ($value as $v) { + if (null !== $v) { + call_user_func([$p, 'add' . $key], $v); } } - } } $manager->persist($p); - echo "add person'".$p->__toString()."'\n"; + echo "add person'" . $p->__toString() . "'\n"; } + /** + * fill a person array with default value. + * + * @param string[] $specific + */ + private function fillWithDefault(array $specific) + { + return array_merge([ + 'Birthdate' => '1960-10-12', + 'PlaceOfBirth' => 'Ottignies Louvain-La-Neuve', + 'Gender' => Person::MALE_GENDER, + 'Email' => "Email d'un ami: roger@tt.com", + 'CountryOfBirth' => 'BE', + 'Nationality' => 'BE', + 'CFData' => [], + 'Address' => null, + ], $specific); + } + + private function getCountry($countryCode) + { + if (null === $countryCode) { + return null; + } + + return $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:Country') + ->findOneByCountryCode($countryCode); + } /** - * Create a random point + * Create a random address. + * + * @return Address + */ + private function getRandomAddress() + { + return (new Address()) + ->setStreetAddress1($this->faker->streetAddress) + ->setStreetAddress2( + rand(0, 9) > 5 ? $this->faker->streetAddress : '' + ) + ->setPoint( + rand(0, 9) > 5 ? $this->getRandomPoint() : null + ) + ->setPostcode($this->getReference( + LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)] + )) + ->setValidFrom($this->faker->dateTimeBetween('-5 years')); + } + + /** + * Create a random point. * * @return Point */ @@ -239,165 +386,7 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con $latBrussels = 50.84676; $lon = $lonBrussels + 0.01 * rand(-5, 5); $lat = $latBrussels + 0.01 * rand(-5, 5); + return Point::fromLonLat($lon, $lat); } - - - /** - * Create a random address - * - * @return Address - */ - private function getRandomAddress() - { - return (new Address()) - ->setStreetAddress1($this->faker->streetAddress) - ->setStreetAddress2( - rand(0,9) > 5 ? $this->faker->streetAddress : '' - ) - ->setPoint( - rand(0,9) > 5 ? $this->getRandomPoint() : NULL - ) - ->setPostcode($this->getReference( - LoadPostalCodes::$refs[array_rand(LoadPostalCodes::$refs)] - )) - ->setValidFrom($this->faker->dateTimeBetween('-5 years')) - ; - } - - private function getCountry($countryCode) - { - if ($countryCode === NULL) { - return NULL; - } - return $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:Country') - ->findOneByCountryCode($countryCode); - } - - private $maritalStatusRef = ['ms_single', 'ms_married', 'ms_widow', 'ms_separat', - 'ms_divorce', 'ms_legalco', 'ms_unknown']; - - private $firstNamesMale = array("Jean", "Mohamed", "Alfred", "Robert", "Justin", "Brian", - "Compère", "Jean-de-Dieu", "Charles", "Pierre", "Luc", "Mathieu", "Alain", "Etienne", "Eric", - "Corentin", "Gaston", "Spirou", "Fantasio", "Mahmadou", "Mohamidou", "Vursuv", "Youssef" ); - - private $firstNamesFemale = array("Svedana", "Sevlatina", "Irène", "Marcelle", - "Corentine", "Alfonsine", "Caroline", "Solange", "Gostine", "Fatoumata", "Nicole", - "Groseille", "Chana", "Oxana", "Ivana", "Julie", "Tina", "Adèle" ); - - private $lastNames = array("Diallo", "Bah", "Gaillot", "Martin"); - - private $lastNamesTrigrams = array("fas", "tré", "hu", 'blart', 'van', 'der', 'lin', 'den', - 'ta', 'mi', 'net', 'gna', 'bol', 'sac', 'ré', 'jo', 'du', 'pont', 'cas', 'tor', 'rob', 'al', - 'ma', 'gone', 'car',"fu", "ka", "lot", "no", "va", "du", "bu", "su", "jau", "tte", 'sir', - "lo", 'to', "cho", "car", 'mo','zu', 'qi', 'mu'); - - private $genders = array(Person::MALE_GENDER, Person::FEMALE_GENDER); - - private $years = array(); - - private $month = array(); - - private $day = array(); - - private $peoples = array( - array( - 'LastName' => "Depardieu", - 'FirstName' => "Gérard", - 'Birthdate' => "1948-12-27", - 'PlaceOfBirth' => "Châteauroux", - 'Gender' => Person::MALE_GENDER, - 'CountryOfBirth' => 'FR', - 'Nationality' => 'RU', - 'center' => 'centerA', - 'maritalStatus' => 'ms_divorce', - 'accompanyingPeriods' => [ - [ - 'from' => '2015-02-01', - 'to' => '2015-10-30', - 'remark' => 'oops', - ],[ - 'from' => '2017-06-01', - 'to' => '2018-03-30', - 'remark' => 'argg', - ],[ - 'from' => '2019-01-01', - 'to' => '2019-12-31', - 'remark' => 'blob', - ] - ] - ), - array( - //to have a person with same firstname as Gérard Depardieu - 'LastName' => "Depardieu", - 'FirstName' => "Jean", - 'Birthdate' => "1960-10-12", - 'CountryOfBirth' => 'FR', - 'Nationality' => 'FR', - 'center' => 'centerA', - 'maritalStatus' => 'ms_divorce' - ), - array( - //to have a person with same birthdate of Gérard Depardieu - 'LastName' => 'Van Snick', - 'FirstName' => 'Bart', - 'Birthdate' => '1948-12-27', - 'center' => 'centerA', - 'maritalStatus' => 'ms_legalco' - ), - array( - //to have a woman with Depardieu as FirstName - 'LastName' => 'Depardieu', - 'FirstName' => 'Charline', - 'Gender' => Person::FEMALE_GENDER, - 'center' => 'centerA', - 'maritalStatus' => 'ms_legalco' - ), - array( - //to have a special character in lastName - 'LastName' => 'Manço', - 'FirstName' => 'Étienne', - 'center' => 'centerA', - 'maritalStatus' => 'ms_unknown' - ), - array( - //to have true duplicate person - 'LastName' => "Depardieu", - 'FirstName' => "Jean", - 'Birthdate' => "1960-10-12", - 'CountryOfBirth' => 'FR', - 'Nationality' => 'FR', - 'center' => 'centerA', - 'maritalStatus' => 'ms_divorce' - ), - array( - //to have false duplicate person - 'LastName' => "Depardieu", - 'FirstName' => "Jeanne", - 'Birthdate' => "1966-11-13", - 'CountryOfBirth' => 'FR', - 'Nationality' => 'FR', - 'center' => 'centerA', - 'maritalStatus' => 'ms_legalco' - ), - ); - - - private function addAccompanyingPeriods(Person $person, array $periods, ObjectManager $manager) - { - foreach ($periods as $period) { - - echo "adding new past Accompanying Period..\n"; - - /** @var AccompanyingPeriod $accompanyingPeriod */ - $accompanyingPeriod = new AccompanyingPeriod(new \DateTime($period['from'])); - $accompanyingPeriod - ->setClosingDate(new \DateTime($period['to'])) - ->setRemark($period['remark']) - ; - - $person->addAccompanyingPeriod($accompanyingPeriod); - } - } } diff --git a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php index c8593d1fd..1f5e95b27 100644 --- a/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php +++ b/src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadPersonACL.php @@ -1,37 +1,25 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\Entity\RoleScope; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; +use Chill\PersonBundle\Security\Authorization\PersonVoter; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; /** * Add a role CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE for all groups except administrative, - * and a role CHILL_PERSON_SEE for administrative - * - * @author Julien Fastré + * and a role CHILL_PERSON_SEE for administrative. */ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface { @@ -40,13 +28,12 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface return 9600; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); $scopeSocial = $this->getReference('scope_social'); - + //create permission group switch ($permissionsGroup->getName()) { case 'social': @@ -60,13 +47,13 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface ); $roleScopeUpdate = (new RoleScope()) - ->setRole('CHILL_PERSON_UPDATE') - ->setScope(null); + ->setRole('CHILL_PERSON_UPDATE') + ->setScope(null); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreate = (new RoleScope()) - ->setRole('CHILL_PERSON_CREATE') - ->setScope(null); + ->setRole('CHILL_PERSON_CREATE') + ->setScope(null); $permissionsGroup->addRoleScope($roleScopeCreate); $roleScopeDuplicate = (new RoleScope()) @@ -75,33 +62,33 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface $permissionsGroup->addRoleScope($roleScopeDuplicate); $roleScopeList = (new RoleScope()) - ->setRole(PersonVoter::LISTS) - ->setScope(null); + ->setRole(PersonVoter::LISTS) + ->setScope(null); $permissionsGroup->addRoleScope($roleScopeList); $roleScopeStats = (new RoleScope()) - ->setRole(PersonVoter::STATS) - ->setScope(null); + ->setRole(PersonVoter::STATS) + ->setScope(null); $permissionsGroup->addRoleScope($roleScopeStats); $manager->persist($roleScopeUpdate); $manager->persist($roleScopeCreate); $manager->persist($roleScopeDuplicate); - + break; + case 'administrative': printf("Adding CHILL_PERSON_SEE to %s permission group \n", $permissionsGroup->getName()); $roleScopeSee = (new RoleScope()) - ->setRole('CHILL_PERSON_SEE') - ->setScope(null); + ->setRole('CHILL_PERSON_SEE') + ->setScope(null); $permissionsGroup->addRoleScope($roleScopeSee); $manager->persist($roleScopeSee); + break; } - } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 84b8bb397..64d62fa77 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -1,50 +1,36 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\DependencyInjection; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader; -use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Chill\MainBundle\DependencyInjection\MissingBundleException; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\MainBundle\Security\Authorization\ChillExportVoter; use Chill\PersonBundle\Doctrine\DQL\AddressPart; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Exception; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; +use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; /** * Class ChillPersonExtension - * Loads and manages your bundle configuration + * Loads and manages your bundle configuration. * * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html} - * @package Chill\PersonBundle\DependencyInjection */ class ChillPersonExtension extends Extension implements PrependExtensionInterface { - /** - * {@inheritDoc} - * @param array $configs - * @param ContainerBuilder $container - * @throws \Exception + * @throws Exception */ public function load(array $configs, ContainerBuilder $container) { @@ -52,16 +38,20 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $config = $this->processConfiguration($configuration, $configs); // set configuration for validation - $container->setParameter('chill_person.validation.birtdate_not_before', - $config['validation']['birthdate_not_after']); + $container->setParameter( + 'chill_person.validation.birtdate_not_before', + $config['validation']['birthdate_not_after'] + ); $this->handlePersonFieldsParameters($container, $config['person_fields']); $this->handleAccompanyingPeriodsFieldsParameters($container, $config['accompanying_periods_fields']); - $container->setParameter('chill_person.allow_multiple_simultaneous_accompanying_periods', - $config['allow_multiple_simultaneous_accompanying_periods']); + $container->setParameter( + 'chill_person.allow_multiple_simultaneous_accompanying_periods', + $config['allow_multiple_simultaneous_accompanying_periods'] + ); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/widgets.yaml'); $loader->load('services/exports.yaml'); @@ -80,10 +70,12 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $loader->load('services/security.yaml'); // load service advanced search only if configure - if ($config['search']['search_by_phone'] != 'never') { + if ('never' != $config['search']['search_by_phone']) { $loader->load('services/search_by_phone.yaml'); - $container->setParameter('chill_person.search.search_by_phone', - $config['search']['search_by_phone']); + $container->setParameter( + 'chill_person.search.search_by_phone', + $config['search']['search_by_phone'] + ); } if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') { @@ -92,70 +84,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac } /** - * @param ContainerBuilder $container - * @param $config - */ - private function handlePersonFieldsParameters(ContainerBuilder $container, $config) - { - if (array_key_exists('enabled', $config)) { - unset($config['enabled']); - } - - $container->setParameter('chill_person.person_fields', $config); - - foreach ($config as $key => $value) { - switch($key) { - case 'accompanying_period': - $container->setParameter('chill_person.accompanying_period', $value); - break; - default: - $container->setParameter('chill_person.person_fields.'.$key, $value); - break; - } - } - } - - /** - * @param ContainerBuilder $container - * @param $config - */ - private function handleAccompanyingPeriodsFieldsParameters(ContainerBuilder $container, $config) - { - $container->setParameter('chill_person.accompanying_period_fields', $config); - - foreach ($config as $key => $value) { - switch($key) { - case 'enabled': - break; - default: - $container->setParameter('chill_person.accompanying_period_fields.'.$key, $value); - break; - } - } - } - - /** - * @param ContainerBuilder $container - * @throws MissingBundleException - */ - private function declarePersonAsCustomizable (ContainerBuilder $container) - { - $bundles = $container->getParameter('kernel.bundles'); - if (!isset($bundles['ChillCustomFieldsBundle'])) { - throw new MissingBundleException('ChillCustomFieldsBundle'); - } - - $container->prependExtensionConfig('chill_custom_fields', - array('customizables_entities' => - array( - array('class' => 'Chill\PersonBundle\Entity\Person', 'name' => 'PersonEntity') - ) - ) - ); - } - - /** - * @param ContainerBuilder $container * @throws MissingBundleException */ public function prepend(ContainerBuilder $container) @@ -168,102 +96,31 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac //add person_fields parameter as global $chillPersonConfig = $container->getExtensionConfig($this->getAlias()); $config = $this->processConfiguration(new Configuration(), $chillPersonConfig); - $twigConfig = array( - 'globals' => array( - 'chill_person' => array( - 'fields' => $config['person_fields'] - ), + $twigConfig = [ + 'globals' => [ + 'chill_person' => [ + 'fields' => $config['person_fields'], + ], 'chill_accompanying_periods' => [ - 'fields' => $config['accompanying_periods_fields'] - ] - ), - 'form_themes' => array('ChillPersonBundle:Export:ListPersonFormFields.html.twig') - ); + 'fields' => $config['accompanying_periods_fields'], + ], + ], + 'form_themes' => ['ChillPersonBundle:Export:ListPersonFormFields.html.twig'], + ]; $container->prependExtensionConfig('twig', $twigConfig); - $this-> declarePersonAsCustomizable($container); + $this->declarePersonAsCustomizable($container); //declare routes for person bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillPersonBundle/config/routes.yaml' - ) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillPersonBundle/config/routes.yaml', + ], + ], + ]); } - /** - * Add a widget "add a person" on the homepage, automatically - * - * @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container - */ - protected function prependHomepageWidget(containerBuilder $container) - { - $container->prependExtensionConfig('chill_main', array( - 'widgets' => array( - 'homepage' => array( - array( - 'widget_alias' => 'add_person', - 'order' => 2 - ) - ) - ) - )); - } - - /** - * Add role hierarchy. - * - * @param ContainerBuilder $container - */ - protected function prependRoleHierarchy(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - 'CHILL_PERSON_UPDATE' => array('CHILL_PERSON_SEE'), - 'CHILL_PERSON_CREATE' => array('CHILL_PERSON_SEE'), - PersonVoter::LISTS => [ ChillExportVoter::EXPORT ], - PersonVoter::STATS => [ ChillExportVoter::EXPORT ] - ) - )); - } - - /** - * Add DQL function linked with person - * - * @param ContainerBuilder $container - */ - protected function prependDoctrineDQL(ContainerBuilder $container) - { - //add DQL function to ORM (default entity_manager) - - $container->prependExtensionConfig('doctrine', array( - 'orm' => array( - 'dql' => array( - 'string_functions' => array( - 'GET_PERSON_ADDRESS_ADDRESS_ID' => AddressPart\AddressPartAddressId::class, - 'GET_PERSON_ADDRESS_STREET_ADDRESS_1' => AddressPart\AddressPartStreetAddress1::class, - 'GET_PERSON_ADDRESS_STREET_ADDRESS_2' => AddressPart\AddressPartStreetAddress2::class, - 'GET_PERSON_ADDRESS_VALID_FROM' => AddressPart\AddressPartValidFrom::class, - 'GET_PERSON_ADDRESS_POSTCODE_LABEL' => AddressPart\AddressPartPostCodeLabel::class, - 'GET_PERSON_ADDRESS_POSTCODE_CODE' => AddressPart\AddressPartPostCodeCode::class, - 'GET_PERSON_ADDRESS_POSTCODE_ID' => AddressPart\AddressPartPostCodeId::class, - 'GET_PERSON_ADDRESS_COUNTRY_NAME' => AddressPart\AddressPartCountryName::class, - 'GET_PERSON_ADDRESS_COUNTRY_CODE' => AddressPart\AddressPartCountryCode::class, - 'GET_PERSON_ADDRESS_COUNTRY_ID' => AddressPart\AddressPartCountryId::class, - ), - 'numeric_functions' => [ - 'GET_PERSON_ADDRESS_ISNOADDRESS' => AddressPart\AddressPartIsNoAddress::class, - ] - ) - ) - )); - } - - /** - * @param ContainerBuilder $container - */ protected function prependCruds(ContainerBuilder $container) { $container->prependExtensionConfig('chill_main', [ @@ -277,17 +134,17 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'actions' => [ 'index' => [ 'template' => '@ChillPerson/ClosingMotive/index.html.twig', - 'role' => 'ROLE_ADMIN' + 'role' => 'ROLE_ADMIN', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/ClosingMotive/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/ClosingMotive/edit.html.twig', - ] - ] + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\MaritalStatus::class, @@ -300,15 +157,15 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/MaritalStatus/index.html.twig', ], - 'new' => [ + 'new' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/MaritalStatus/new.html.twig', ], - 'edit' => [ + 'edit' => [ 'role' => 'ROLE_ADMIN', 'template' => '@ChillPerson/MaritalStatus/edit.html.twig', - ] - ] + ], + ], ], ], 'apis' => [ @@ -319,24 +176,23 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'controller' => \Chill\PersonBundle\Controller\AccompanyingCourseApiController::class, 'actions' => [ '_entity' => [ - 'roles' => [ - Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE - ] + 'roles' => [ + Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, + ], ], 'participation' => [ 'methods' => [ - Request::METHOD_POST => true, + Request::METHOD_POST => true, Request::METHOD_DELETE => true, Request::METHOD_GET => false, Request::METHOD_HEAD => false, ], - 'roles' => [ + 'roles' => [ Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, - Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE - ] - ] - - ] + Request::METHOD_DELETE => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, + ], + ], + ], ], [ 'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod\Origin::class, @@ -346,20 +202,150 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac 'base_role' => 'ROLE_USER', 'actions' => [ '_index' => [ - 'methods' => [ + 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true + Request::METHOD_HEAD => true, ], ], '_entity' => [ - 'methods' => [ + 'methods' => [ Request::METHOD_GET => true, - Request::METHOD_HEAD => true - ] + Request::METHOD_HEAD => true, + ], ], - ] - ] - ] + ], + ], + ], ]); } + + /** + * Add DQL function linked with person. + */ + protected function prependDoctrineDQL(ContainerBuilder $container) + { + //add DQL function to ORM (default entity_manager) + + $container->prependExtensionConfig('doctrine', [ + 'orm' => [ + 'dql' => [ + 'string_functions' => [ + 'GET_PERSON_ADDRESS_ADDRESS_ID' => AddressPart\AddressPartAddressId::class, + 'GET_PERSON_ADDRESS_STREET_ADDRESS_1' => AddressPart\AddressPartStreetAddress1::class, + 'GET_PERSON_ADDRESS_STREET_ADDRESS_2' => AddressPart\AddressPartStreetAddress2::class, + 'GET_PERSON_ADDRESS_VALID_FROM' => AddressPart\AddressPartValidFrom::class, + 'GET_PERSON_ADDRESS_POSTCODE_LABEL' => AddressPart\AddressPartPostCodeLabel::class, + 'GET_PERSON_ADDRESS_POSTCODE_CODE' => AddressPart\AddressPartPostCodeCode::class, + 'GET_PERSON_ADDRESS_POSTCODE_ID' => AddressPart\AddressPartPostCodeId::class, + 'GET_PERSON_ADDRESS_COUNTRY_NAME' => AddressPart\AddressPartCountryName::class, + 'GET_PERSON_ADDRESS_COUNTRY_CODE' => AddressPart\AddressPartCountryCode::class, + 'GET_PERSON_ADDRESS_COUNTRY_ID' => AddressPart\AddressPartCountryId::class, + ], + 'numeric_functions' => [ + 'GET_PERSON_ADDRESS_ISNOADDRESS' => AddressPart\AddressPartIsNoAddress::class, + ], + ], + ], + ]); + } + + /** + * Add a widget "add a person" on the homepage, automatically. + * + * @param \Chill\PersonBundle\DependencyInjection\containerBuilder $container + */ + protected function prependHomepageWidget(containerBuilder $container) + { + $container->prependExtensionConfig('chill_main', [ + 'widgets' => [ + 'homepage' => [ + [ + 'widget_alias' => 'add_person', + 'order' => 2, + ], + ], + ], + ]); + } + + /** + * Add role hierarchy. + */ + protected function prependRoleHierarchy(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + 'CHILL_PERSON_UPDATE' => ['CHILL_PERSON_SEE'], + 'CHILL_PERSON_CREATE' => ['CHILL_PERSON_SEE'], + PersonVoter::LISTS => [ChillExportVoter::EXPORT], + PersonVoter::STATS => [ChillExportVoter::EXPORT], + ], + ]); + } + + /** + * @throws MissingBundleException + */ + private function declarePersonAsCustomizable(ContainerBuilder $container) + { + $bundles = $container->getParameter('kernel.bundles'); + + if (!isset($bundles['ChillCustomFieldsBundle'])) { + throw new MissingBundleException('ChillCustomFieldsBundle'); + } + + $container->prependExtensionConfig( + 'chill_custom_fields', + ['customizables_entities' => [ + ['class' => 'Chill\PersonBundle\Entity\Person', 'name' => 'PersonEntity'], + ], + ] + ); + } + + /** + * @param $config + */ + private function handleAccompanyingPeriodsFieldsParameters(ContainerBuilder $container, $config) + { + $container->setParameter('chill_person.accompanying_period_fields', $config); + + foreach ($config as $key => $value) { + switch ($key) { + case 'enabled': + break; + + default: + $container->setParameter('chill_person.accompanying_period_fields.' . $key, $value); + + break; + } + } + } + + /** + * @param $config + */ + private function handlePersonFieldsParameters(ContainerBuilder $container, $config) + { + if (array_key_exists('enabled', $config)) { + unset($config['enabled']); + } + + $container->setParameter('chill_person.person_fields', $config); + + foreach ($config as $key => $value) { + switch ($key) { + case 'accompanying_period': + $container->setParameter('chill_person.accompanying_period', $value); + + break; + + default: + $container->setParameter('chill_person.person_fields.' . $key, $value); + + break; + } + } + } } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php b/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php index 1ee7782d3..e0a617be2 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/CompilerPass/AccompanyingPeriodTimelineCompilerPass.php @@ -1,29 +1,22 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\PersonBundle\DependencyInjection\CompilerPass; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; /** - * Remove services which add AccompanyingPeriod to timeline if - * accompanying_periods are set to `hidden` + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\PersonBundle\DependencyInjection\CompilerPass; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +use function in_array; + +/** + * Remove services which add AccompanyingPeriod to timeline if + * accompanying_periods are set to `hidden`. */ class AccompanyingPeriodTimelineCompilerPass implements CompilerPassInterface { @@ -33,34 +26,33 @@ class AccompanyingPeriodTimelineCompilerPass implements CompilerPassInterface if ($container->getParameter('chill_person.accompanying_period') !== 'hidden') { return; } - + $definitions = [ 'chill.person.timeline.accompanying_period_opening', - 'chill.person.timeline.accompanying_period_closing' + 'chill.person.timeline.accompanying_period_closing', ]; - - foreach($definitions as $definition) { + + foreach ($definitions as $definition) { $container - ->removeDefinition($definition) - ; + ->removeDefinition($definition); } - + $definition = $container->getDefinition('chill.main.timeline_builder'); - - // we have to remove all methods call, and re-add them if not linked + + // we have to remove all methods call, and re-add them if not linked // to this service $calls = $definition->getMethodCalls(); - - foreach($calls as list($method, $arguments)) { - if ($method !== 'addProvider') { + + foreach ($calls as [$method, $arguments]) { + if ('addProvider' !== $method) { continue; } - + $definition->removeMethodCall('addProvider'); - - if (FALSE === \in_array($arguments[1], $definitions)) { + + if (false === in_array($arguments[1], $definitions)) { $definition->addMethodCall($method, $arguments); - } + } } } } diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php index 3ebe3ceb1..945354773 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/Configuration.php @@ -1,147 +1,154 @@ getRootNode('cl_chill_person'); $rootNode - ->canBeDisabled() - ->children() - ->arrayNode('search') - ->canBeDisabled() - ->children() - ->enumNode('search_by_phone') - ->values(['always', 'on-domain', 'never']) - ->defaultValue('on-domain') - ->info('enable search by phone. \'always\' show the result ' + ->canBeDisabled() + ->children() + ->arrayNode('search') + ->canBeDisabled() + ->children() + ->enumNode('search_by_phone') + ->values(['always', 'on-domain', 'never']) + ->defaultValue('on-domain') + ->info('enable search by phone. \'always\' show the result ' . 'on every result. \'on-domain\' will show the result ' . 'only if the domain is given in the search box. ' . '\'never\' disable this feature') - ->end() - ->end() //children for 'search', parent = array node 'search' - ->end() // array 'search', parent = children of root - ->arrayNode('validation') - ->canBeDisabled() - ->children() - ->scalarNode('birthdate_not_after') - ->info($this->validationBirthdateNotAfterInfos) - ->defaultValue('P1D') - ->validate() - ->ifTrue(function($period) { - try { - $interval = new \DateInterval($period); - } catch (\Exception $ex) { - return true; - } - return false; - }) - ->thenInvalid('Invalid period for birthdate validation : "%s" ' + ->end() + ->end() //children for 'search', parent = array node 'search' + ->end() // array 'search', parent = children of root + ->arrayNode('validation') + ->canBeDisabled() + ->children() + ->scalarNode('birthdate_not_after') + ->info($this->validationBirthdateNotAfterInfos) + ->defaultValue('P1D') + ->validate() + ->ifTrue(function ($period) { + try { + $interval = new DateInterval($period); + } catch (Exception $ex) { + return true; + } + + return false; + }) + ->thenInvalid('Invalid period for birthdate validation : "%s" ' . 'The parameter should match duration as defined by ISO8601 : ' . 'https://en.wikipedia.org/wiki/ISO_8601#Durations') - ->end() // birthdate_not_after, parent = children of validation - - ->end() // children for 'validation', parent = validation - ->end() //validation, parent = children of root - ->end() // children of root, parent = root - ->arrayNode('person_fields') - ->canBeDisabled() - ->children() - ->append($this->addFieldNode('place_of_birth')) - ->append($this->addFieldNode('email')) - ->append($this->addFieldNode('phonenumber')) - ->append($this->addFieldNode('mobilenumber')) - ->append($this->addFieldNode('contact_info')) - ->append($this->addFieldNode('nationality')) - ->append($this->addFieldNode('country_of_birth')) - ->append($this->addFieldNode('marital_status')) - ->append($this->addFieldNode('spoken_languages')) - ->append($this->addFieldNode('address')) - ->append($this->addFieldNode('accompanying_period')) - ->append($this->addFieldNode('memo')) - ->arrayNode('alt_names') - ->defaultValue([]) - ->arrayPrototype() - ->children() - ->scalarNode('key') - ->isRequired()->cannotBeEmpty() - ->end() - ->arrayNode('labels') - ->children() - ->scalarNode('lang')->isRequired()->cannotBeEmpty() - ->example('fr') - ->end() - ->scalarNode('label')->isRequired()->cannotBeEmpty() - ->example('Nom de jeune fille') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() //children for 'person_fields', parent = array 'person_fields' - ->end() // person_fields, parent = children of root - ->arrayNode('accompanying_periods_fields') - ->canBeDisabled() - ->children() - ->append($this->addFieldNode('user')) - ->append($this->addFieldNode('createdBy')) - ->append($this->addFieldNode('step')) - ->append($this->addFieldNode('origin')) - ->append($this->addFieldNode('intensity')) - ->append($this->addFieldNode('scopes')) - ->append($this->addFieldNode('requestor')) - ->append($this->addFieldNode('anonymous')) - ->append($this->addFieldNode('emergency')) - ->append($this->addFieldNode('confidential')) - ->end() //children for 'accompanying_person_fields', parent = array 'person_fields' - ->end() // paccompanying_person_fields, parent = children of root - ->booleanNode('allow_multiple_simultaneous_accompanying_periods') - ->info('Can we have more than one simultaneous accompanying period in the same time. Default false.') - ->defaultValue(false) - ->end() - ->end() // children of 'root', parent = root - ; - + ->end() // birthdate_not_after, parent = children of validation + ->end() // children for 'validation', parent = validation + ->end() //validation, parent = children of root + ->end() // children of root, parent = root + ->arrayNode('person_fields') + ->canBeDisabled() + ->children() + ->append($this->addFieldNode('place_of_birth')) + ->append($this->addFieldNode('email')) + ->append($this->addFieldNode('phonenumber')) + ->append($this->addFieldNode('mobilenumber')) + ->append($this->addFieldNode('contact_info')) + ->append($this->addFieldNode('nationality')) + ->append($this->addFieldNode('country_of_birth')) + ->append($this->addFieldNode('marital_status')) + ->append($this->addFieldNode('spoken_languages')) + ->append($this->addFieldNode('address')) + ->append($this->addFieldNode('accompanying_period')) + ->append($this->addFieldNode('memo')) + ->arrayNode('alt_names') + ->defaultValue([]) + ->arrayPrototype() + ->children() + ->scalarNode('key') + ->isRequired()->cannotBeEmpty() + ->end() + ->arrayNode('labels') + ->children() + ->scalarNode('lang')->isRequired()->cannotBeEmpty() + ->example('fr') + ->end() + ->scalarNode('label')->isRequired()->cannotBeEmpty() + ->example('Nom de jeune fille') + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() + ->end() //children for 'person_fields', parent = array 'person_fields' + ->end() // person_fields, parent = children of root + ->arrayNode('accompanying_periods_fields') + ->canBeDisabled() + ->children() + ->append($this->addFieldNode('user')) + ->append($this->addFieldNode('createdBy')) + ->append($this->addFieldNode('step')) + ->append($this->addFieldNode('origin')) + ->append($this->addFieldNode('intensity')) + ->append($this->addFieldNode('scopes')) + ->append($this->addFieldNode('requestor')) + ->append($this->addFieldNode('anonymous')) + ->append($this->addFieldNode('emergency')) + ->append($this->addFieldNode('confidential')) + ->end() //children for 'accompanying_person_fields', parent = array 'person_fields' + ->end() // paccompanying_person_fields, parent = children of root + ->booleanNode('allow_multiple_simultaneous_accompanying_periods') + ->info('Can we have more than one simultaneous accompanying period in the same time. Default false.') + ->defaultValue(false) + ->end() + ->end(); // children of 'root', parent = root return $treeBuilder; } private function addFieldNode($key) { - $tree = new TreeBuilder($key,'enum'); + $tree = new TreeBuilder($key, 'enum'); $node = $tree->getRootNode($key); - - switch($key) { + + switch ($key) { case 'accompanying_period': - $info = "If the accompanying periods are shown"; + $info = 'If the accompanying periods are shown'; + break; + default: - $info = "If the field $key must be shown"; + $info = "If the field {$key} must be shown"; + break; } $node - ->values(array('hidden', 'visible')) + ->values(['hidden', 'visible']) ->defaultValue('visible') ->info($info) ->end(); diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart.php index 98e362dfb..c9b7a6ca2 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL; use Doctrine\ORM\Query\AST\Functions\FunctionNode; @@ -23,70 +15,64 @@ use Doctrine\ORM\Query\Parser; use Doctrine\ORM\Query\SqlWalker; /** - * * USAGE GET_ADDRESS_(person.id, :date, 'postcode') where part * should be replace by the part of the address. - * + * * This function return the current address part at the given date, for the * given person (identified by his id) - * - * The aim of this function is to be used within reports * - * @author Julien Fastré + * The aim of this function is to be used within reports */ abstract class AddressPart extends FunctionNode { - public $fields = array( - 'address_id', - 'streetaddress1', - 'streetaddress2', - 'validfrom', - 'postcode_label', - 'postcode_code', - 'postcode_id', - 'country_name', - 'country_code', - 'country_id' - ); - + public $fields = [ + 'address_id', + 'streetaddress1', + 'streetaddress2', + 'validfrom', + 'postcode_label', + 'postcode_code', + 'postcode_id', + 'country_name', + 'country_code', + 'country_id', + ]; + /** - * - * @var \Doctrine\ORM\Query\AST\Node - */ - private $pid; - - /** - * * @var \Doctrine\ORM\Query\AST\Node */ private $date; - + /** - * * @var \Doctrine\ORM\Query\AST\Node */ private $part; - + /** - * return the part of the address - * - * Should be one value of the "public" amongst - * 'address_id', 'streetaddress1', - * 'streetaddress2', 'validfrom', 'postcode_label', 'postcode_code', + * @var \Doctrine\ORM\Query\AST\Node + */ + private $pid; + + /** + * return the part of the address. + * + * Should be one value of the "public" amongst + * 'address_id', 'streetaddress1', + * 'streetaddress2', 'validfrom', 'postcode_label', 'postcode_code', * 'postcode_id', 'country_name', 'country_code', 'country_id', 'isnoaddress' - * + * * @return string */ abstract public function getPart(); - + public function getSql(SqlWalker $sqlWalker) { return sprintf( - 'get_last_address_%s(%s, %s)', + 'get_last_address_%s(%s, %s)', $this->getPart(), $this->pid->dispatch($sqlWalker), $this->date->dispatch($sqlWalker) - ); + ); } public function parse(Parser $parser) diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartAddressId.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartAddressId.php index 2f40796cf..698bb65ff 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartAddressId.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartAddressId.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartAddressId extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryCode.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryCode.php index e997dbb91..5e558eac3 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryCode.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryCode.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartCountryCode extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryId.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryId.php index ab0ab0da2..b0379b934 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryId.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryId.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartCountryId extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryName.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryName.php index c37902909..7eb1408fa 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryName.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartCountryName.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartCountryName extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartIsNoAddress.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartIsNoAddress.php index bd08bb4df..0676659d3 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartIsNoAddress.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartIsNoAddress.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartIsNoAddress extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php index ce792cede..eb786df22 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeCode.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartPostCodeCode extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php index 5400a04a7..0f9885b8b 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeId.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartPostCodeId extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php index ab36a8c46..3814ab5a3 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartPostCodeLabel.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartPostCodeLabel extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php index c06cf2b07..30d87f452 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress1.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartStreetAddress1 extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php index 739120e5e..e52ce38ba 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartStreetAddress2.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartStreetAddress2 extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartValidFrom.php b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartValidFrom.php index 4a366bf1a..43b271960 100644 --- a/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartValidFrom.php +++ b/src/Bundle/ChillPersonBundle/Doctrine/DQL/AddressPart/AddressPartValidFrom.php @@ -1,29 +1,16 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Doctrine\DQL\AddressPart; use Chill\PersonBundle\Doctrine\DQL\AddressPart; -/** - * - * - * @author Julien Fastré - */ class AddressPartValidFrom extends AddressPart { public function getPart() diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 9eec8e6fb..a10022025 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -1,81 +1,113 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity; use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\AccompanyingPeriod\Origin; use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\ThirdPartyBundle\Entity\ThirdParty; +use DateTime; +use DateTimeImmutable; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Chill\MainBundle\Entity\User; /** - * AccompanyingPeriod Class + * AccompanyingPeriod Class. * * @ORM\Entity(repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriodRepository") * @ORM\Table(name="chill_person_accompanying_period") */ class AccompanyingPeriod { + public const INTENSITIES = [self::INTENSITY_OCCASIONAL, self::INTENSITY_REGULAR]; + /** - * Mark an accompanying period as "occasional" - * + * Mark an accompanying period as "occasional". + * * used in INTENSITY */ public const INTENSITY_OCCASIONAL = 'occasional'; - + /** - * Mark an accompanying period as "regular" - * + * Mark an accompanying period as "regular". + * * used in INTENSITY */ public const INTENSITY_REGULAR = 'regular'; - - public const INTENSITIES = [self::INTENSITY_OCCASIONAL, self::INTENSITY_REGULAR]; - - /** - * Mark an accompanying period as "draft". - * - * This means that the accompanying period is not yet - * confirmed by the creator - */ - public const STEP_DRAFT = 'DRAFT'; - + /** * Mark an accompanying period as "confirmed". - * - * This means that the accompanying period **is** + * + * This means that the accompanying period **is** * confirmed by the creator */ public const STEP_CONFIRMED = 'CONFIRMED'; - + /** - * @var integer + * Mark an accompanying period as "draft". + * + * This means that the accompanying period is not yet + * confirmed by the creator + */ + public const STEP_DRAFT = 'DRAFT'; + + /** + * @var DateTime + * + * @ORM\Column(type="date", nullable=true) + */ + private $closingDate; + + /** + * @var AccompanyingPeriod\ClosingMotive + * + * @ORM\ManyToOne( + * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive") + * @ORM\JoinColumn(nullable=true) + */ + private $closingMotive; + + /** + * @var Collection + * + * @ORM\OneToMany(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Comment", + * mappedBy="accompanyingPeriod" + * ) + */ + private $comments; + + /** + * @var bool + * @ORM\Column(type="boolean") + */ + private $confidential = false; + + /** + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=true) + */ + private $createdBy; + + /** + * @var bool + * @ORM\Column(type="boolean") + */ + private $emergency = false; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -84,18 +116,32 @@ class AccompanyingPeriod private $id; /** - * @var \DateTime + * @var string + * @ORM\Column(type="string", nullable=true) + */ + private $intensity; + + /** + * @var DateTime * * @ORM\Column(type="date") */ private $openingDate; /** - * @var \DateTime - * - * @ORM\Column(type="date", nullable=true) + * @ORM\ManyToOne(targetEntity=Origin::class) + * @ORM\JoinColumn(nullable=true) */ - private $closingDate = null; + private $origin; + + /** + * @var Collection + * + * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, + * mappedBy="accompanyingPeriod", + * cascade={"persist", "refresh", "remove", "merge", "detach"}) + */ + private $participations; /** * @var string @@ -105,75 +151,10 @@ class AccompanyingPeriod private $remark = ''; /** - * @var Collection - * - * @ORM\OneToMany(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\Comment", - * mappedBy="accompanyingPeriod" - * ) + * @var bool + * @ORM\Column(type="boolean") */ - private $comments; - - /** - * @var Collection - * - * @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class, - * mappedBy="accompanyingPeriod", - * cascade={"persist", "refresh", "remove", "merge", "detach"}) - */ - private $participations; - - /** - * @var AccompanyingPeriod\ClosingMotive - * - * @ORM\ManyToOne( - * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive") - * @ORM\JoinColumn(nullable=true) - */ - private $closingMotive = null; - - /** - * @ORM\ManyToOne(targetEntity=User::class) - * @ORM\JoinColumn(nullable=true) - */ - private $user; - - /** - * @ORM\ManyToOne(targetEntity=User::class) - * @ORM\JoinColumn(nullable=true) - */ - private $createdBy; - - /** - * @var string - * @ORM\Column(type="string", length=32, nullable=true) - */ - private $step = self::STEP_DRAFT; - - /** - * @ORM\ManyToOne(targetEntity=Origin::class) - * @ORM\JoinColumn(nullable=true) - */ - private $origin; - - /** - * @var string - * @ORM\Column(type="string", nullable=true) - */ - private $intensity; - - /** - * @var Collection - * @ORM\ManyToMany( - * targetEntity=Scope::class, - * cascade={} - * ) - * @ORM\JoinTable( - * name="accompanying_periods_scopes", - * joinColumns={@ORM\JoinColumn(name="accompanying_period_id", referencedColumnName="id")}, - * inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")} - * ) - */ - private $scopes; + private $requestorAnonymous = false; /** * @ORM\ManyToOne(targetEntity=Person::class) @@ -187,24 +168,6 @@ class AccompanyingPeriod */ private $requestorThirdParty; - /** - * @var bool - * @ORM\Column(type="boolean") - */ - private $requestorAnonymous = false; - - /** - * @var bool - * @ORM\Column(type="boolean") - */ - private $emergency = false; - - /** - * @var bool - * @ORM\Column(type="boolean") - */ - private $confidential = false; - /** * @var Collection * @@ -215,114 +178,44 @@ class AccompanyingPeriod */ private $resources; + /** + * @var Collection + * @ORM\ManyToMany( + * targetEntity=Scope::class, + * cascade={} + * ) + * @ORM\JoinTable( + * name="accompanying_periods_scopes", + * joinColumns={@ORM\JoinColumn(name="accompanying_period_id", referencedColumnName="id")}, + * inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")} + * ) + */ + private $scopes; + + /** + * @var string + * @ORM\Column(type="string", length=32, nullable=true) + */ + private $step = self::STEP_DRAFT; + + /** + * @ORM\ManyToOne(targetEntity=User::class) + * @ORM\JoinColumn(nullable=true) + */ + private $user; + /** * AccompanyingPeriod constructor. * - * @param \DateTime $dateOpening * @uses AccompanyingPeriod::setClosingDate() */ - public function __construct(\DateTime $dateOpening) { + public function __construct(DateTime $dateOpening) + { $this->setOpeningDate($dateOpening); $this->participations = new ArrayCollection(); $this->scopes = new ArrayCollection(); } - /** - * Get id - * - * @return integer - */ - public function getId() - { - return $this->id; - } - - /** - * Set openingDate - * - * @param \DateTime $dateOpening - * @return AccompanyingPeriod - */ - public function setOpeningDate($openingDate) - { - $this->openingDate = $openingDate; - - return $this; - } - - /** - * Get openingDate - * - * @return \DateTime - */ - public function getOpeningDate() - { - return $this->openingDate; - } - - /** - * Set closingDate - * - * For closing a Person file, you should use Person::setClosed instead. - * - * @param \DateTime $dateClosing - * @return AccompanyingPeriod - * - */ - public function setClosingDate($closingDate) - { - $this->closingDate = $closingDate; - - return $this; - } - - /** - * Get closingDate - * - * @return \DateTime - */ - public function getClosingDate(): ?\DateTime - { - return $this->closingDate; - } - - /** - * @return boolean - */ - public function isOpen(): bool - { - if ($this->getOpeningDate() > new \DateTimeImmutable('now')) { - return false; - } - - if ($this->getClosingDate() === null) { - return true; - } - - return false; - } - - public function setRemark(string $remark): self - { - if ($remark === null) { - $remark = ''; - } - - $this->remark = $remark; - - return $this; - } - - public function getRemark(): string - { - return $this->remark; - } - - public function getComments(): Collection - { - return $this->comments; - } - public function addComment(Comment $comment): self { $this->comments[] = $comment; @@ -330,63 +223,10 @@ class AccompanyingPeriod return $this; } - public function removeComment(Comment $comment): void - { - $this->comments->removeElement($comment); - } - /** - * Get Participations Collection + * Add Person. */ - public function getParticipations(): Collection - { - return $this->participations; - } - - /** - * Get the participation containing a person - */ - public function getParticipationsContainsPerson(Person $person): Collection - { - return $this->getParticipations($person)->filter( - function(AccompanyingPeriodParticipation $participation) use ($person) { - if ($person === $participation->getPerson()) { - return $participation; - } - }); - } - - /** - * Get the opened participation containing a person - * - * "Open" means that the closed date is NULL - */ - public function getOpenParticipationContainsPerson(Person $person): ?AccompanyingPeriodParticipation - { - $collection = $this->getParticipationsContainsPerson($person)->filter( - function(AccompanyingPeriodParticipation $participation) use ($person) { - if (NULL === $participation->getEndDate()) { - return $participation; - } - }); - - return $collection->count() > 0 ? $collection->first() : NULL; - } - - /** - * Return true if the accompanying period contains a person. - * - * **Note**: this participation can be opened or not. - */ - public function containsPerson(Person $person): bool - { - return $this->getParticipationsContainsPerson($person)->count() > 0; - } - - /** - * Add Person - */ - public function addPerson(Person $person = null): AccompanyingPeriodParticipation + public function addPerson(?Person $person = null): AccompanyingPeriodParticipation { $participation = new AccompanyingPeriodParticipation($this, $person); $this->participations[] = $participation; @@ -394,29 +234,16 @@ class AccompanyingPeriod return $participation; } - /** - * Remove Person - */ - public function removePerson(Person $person): ?AccompanyingPeriodParticipation + public function addResource(Resource $resource): self { - $participation = $this->getOpenParticipationContainsPerson($person); + $this->resources[] = $resource; - if ($participation instanceof AccompanyingPeriodParticipation) { - $participation->setEndDate(new \DateTimeImmutable('now')); - } - - return $participation; + return $this; } - - public function getClosingMotive(): ?ClosingMotive + public function addScope(Scope $scope): self { - return $this->closingMotive; - } - - public function setClosingMotive(ClosingMotive $closingMotive = null): self - { - $this->closingMotive = $closingMotive; + $this->scopes[] = $scope; return $this; } @@ -434,10 +261,11 @@ class AccompanyingPeriod } $participation = $this->participationsContainsPerson($person); - if (!null === $participation) - { + + if (!null === $participation) { $person = $participation->getPerson(); $periods = $person->getAccompanyingPeriodsOrdered(); + return end($periods) === $this; } @@ -445,57 +273,81 @@ class AccompanyingPeriod } /** - */ - public function reOpen(): void - { - $this->setClosingDate(null); - $this->setClosingMotive(null); - } - - /** - * Validation function - */ - public function isDateConsistent(ExecutionContextInterface $context) - { - if ($this->isOpen()) { - return; - } - - if (! $this->isClosingAfterOpening()) { - $context->buildViolation('The date of closing is before the date of opening') - ->atPath('dateClosing') - ->addViolation(); - } - } - - /** - * Returns true if the closing date is after the opening date. + * Return true if the accompanying period contains a person. * - * @return boolean + * **Note**: this participation can be opened or not. */ - public function isClosingAfterOpening(): bool + public function containsPerson(Person $person): bool { - if (null === $this->getClosingDate()) { - return false; - } - $diff = $this->getOpeningDate()->diff($this->getClosingDate()); - - if ($diff->invert === 0) { - return true; - } - return false; + return $this->getParticipationsContainsPerson($person)->count() > 0; } - function getUser(): ?User + /** + * Get closingDate. + * + * @return DateTime + */ + public function getClosingDate(): ?DateTime { - return $this->user; + return $this->closingDate; } - function setUser(User $user): self + public function getClosingMotive(): ?ClosingMotive { - $this->user = $user; + return $this->closingMotive; + } - return $this; + public function getComments(): Collection + { + return $this->comments; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + public function getIntensity(): ?string + { + return $this->intensity; + } + + /** + * Get openingDate. + * + * @return DateTime + */ + public function getOpeningDate() + { + return $this->openingDate; + } + + /** + * Get the opened participation containing a person. + * + * "Open" means that the closed date is NULL + */ + public function getOpenParticipationContainsPerson(Person $person): ?AccompanyingPeriodParticipation + { + $collection = $this->getParticipationsContainsPerson($person)->filter( + function (AccompanyingPeriodParticipation $participation) { + if (null === $participation->getEndDate()) { + return $participation; + } + } + ); + + return $collection->count() > 0 ? $collection->first() : null; } public function getOrigin(): ?Origin @@ -503,35 +355,43 @@ class AccompanyingPeriod return $this->origin; } - public function setOrigin(Origin $origin): self + /** + * Get Participations Collection. + */ + public function getParticipations(): Collection { - $this->origin = $origin; - - return $this; + return $this->participations; } - public function getRequestorPerson(): ?Person + /** + * Get the participation containing a person. + */ + public function getParticipationsContainsPerson(Person $person): Collection { - return $this->requestorPerson; + return $this->getParticipations($person)->filter( + function (AccompanyingPeriodParticipation $participation) use ($person) { + if ($participation->getPerson() === $person) { + return $participation; + } + } + ); } - public function setRequestorPerson(Person $requestorPerson): self + /** + * Get a list of all persons which are participating to this course. + */ + public function getPersons(): Collection { - $this->requestorPerson = ($this->requestorThirdParty === null) ? $requestorPerson : null; - - return $this; + return $this->participations->map( + function (AccompanyingPeriodParticipation $participation) { + return $participation->getPerson(); + } + ); } - public function getRequestorThirdParty(): ?ThirdParty + public function getRemark(): string { - return $this->requestorThirdParty; - } - - public function setRequestorThirdParty(ThirdParty $requestorThirdParty): self - { - $this->requestorThirdParty = ($this->requestorPerson === null) ? $requestorThirdParty : null; - - return $this; + return $this->remark; } /** @@ -542,16 +402,72 @@ class AccompanyingPeriod return $this->requestorPerson ?? $this->requestorThirdParty; } - public function isRequestorAnonymous(): bool + public function getRequestorPerson(): ?Person { - return $this->requestorAnonymous; + return $this->requestorPerson; } - public function setRequestorAnonymous(bool $requestorAnonymous): self + public function getRequestorThirdParty(): ?ThirdParty { - $this->requestorAnonymous = $requestorAnonymous; + return $this->requestorThirdParty; + } - return $this; + public function getResources(): Collection + { + return $this->resources; + } + + public function getScopes(): Collection + { + return $this->scopes; + } + + public function getStep(): ?string + { + return $this->step; + } + + public function getUser(): ?User + { + return $this->user; + } + + /** + * Returns true if the closing date is after the opening date. + */ + public function isClosingAfterOpening(): bool + { + if (null === $this->getClosingDate()) { + return false; + } + $diff = $this->getOpeningDate()->diff($this->getClosingDate()); + + if (0 === $diff->invert) { + return true; + } + + return false; + } + + public function isConfidential(): bool + { + return $this->confidential; + } + + /** + * Validation function. + */ + public function isDateConsistent(ExecutionContextInterface $context) + { + if ($this->isOpen()) { + return; + } + + if (!$this->isClosingAfterOpening()) { + $context->buildViolation('The date of closing is before the date of opening') + ->atPath('dateClosing') + ->addViolation(); + } } public function isEmergency(): bool @@ -559,16 +475,80 @@ class AccompanyingPeriod return $this->emergency; } - public function setEmergency(bool $emergency): self + public function isOpen(): bool { - $this->emergency = $emergency; + if ($this->getOpeningDate() > new DateTimeImmutable('now')) { + return false; + } + + if ($this->getClosingDate() === null) { + return true; + } + + return false; + } + + public function isRequestorAnonymous(): bool + { + return $this->requestorAnonymous; + } + + public function removeComment(Comment $comment): void + { + $this->comments->removeElement($comment); + } + + /** + * Remove Person. + */ + public function removePerson(Person $person): ?AccompanyingPeriodParticipation + { + $participation = $this->getOpenParticipationContainsPerson($person); + + if ($participation instanceof AccompanyingPeriodParticipation) { + $participation->setEndDate(new DateTimeImmutable('now')); + } + + return $participation; + } + + public function removeResource(Resource $resource): void + { + $this->resources->removeElement($resource); + } + + public function removeScope(Scope $scope): void + { + $this->scopes->removeElement($scope); + } + + public function reOpen(): void + { + $this->setClosingDate(null); + $this->setClosingMotive(null); + } + + /** + * Set closingDate. + * + * For closing a Person file, you should use Person::setClosed instead. + * + * @param mixed $closingDate + * + * @return AccompanyingPeriod + */ + public function setClosingDate($closingDate) + { + $this->closingDate = $closingDate; return $this; } - public function isConfidential(): bool + public function setClosingMotive(?ClosingMotive $closingMotive = null): self { - return $this->confidential; + $this->closingMotive = $closingMotive; + + return $this; } public function setConfidential(bool $confidential): self @@ -578,11 +558,6 @@ class AccompanyingPeriod return $this; } - public function getCreatedBy(): ?User - { - return $this->createdBy; - } - public function setCreatedBy(User $createdBy): self { $this->createdBy = $createdBy; @@ -590,23 +565,13 @@ class AccompanyingPeriod return $this; } - public function getStep(): ?string + public function setEmergency(bool $emergency): self { - return $this->step; - } - - public function setStep(string $step): self - { - $this->step = $step; + $this->emergency = $emergency; return $this; } - public function getIntensity(): ?string - { - return $this->intensity; - } - public function setIntensity(string $intensity): self { $this->intensity = $intensity; @@ -614,49 +579,70 @@ class AccompanyingPeriod return $this; } - public function getScopes(): Collection - { - return $this->scopes; - } - - public function addScope(Scope $scope): self - { - $this->scopes[] = $scope; - - return $this; - } - - public function removeScope(Scope $scope): void - { - $this->scopes->removeElement($scope); - } - - public function getResources(): Collection - { - return $this->resources; - } - - public function addResource(Resource $resource): self - { - $this->resources[] = $resource; - - return $this; - } - - public function removeResource(Resource $resource): void - { - $this->resources->removeElement($resource); - } - /** - * Get a list of all persons which are participating to this course + * Set openingDate. + * + * @param mixed $openingDate + * + * @return AccompanyingPeriod */ - public function getPersons(): Collection + public function setOpeningDate($openingDate) { - return $this->participations->map( - function(AccompanyingPeriodParticipation $participation) { - return $participation->getPerson(); - } - ); + $this->openingDate = $openingDate; + + return $this; + } + + public function setOrigin(Origin $origin): self + { + $this->origin = $origin; + + return $this; + } + + public function setRemark(string $remark): self + { + if (null === $remark) { + $remark = ''; + } + + $this->remark = $remark; + + return $this; + } + + public function setRequestorAnonymous(bool $requestorAnonymous): self + { + $this->requestorAnonymous = $requestorAnonymous; + + return $this; + } + + public function setRequestorPerson(Person $requestorPerson): self + { + $this->requestorPerson = (null === $this->requestorThirdParty) ? $requestorPerson : null; + + return $this; + } + + public function setRequestorThirdParty(ThirdParty $requestorThirdParty): self + { + $this->requestorThirdParty = (null === $this->requestorPerson) ? $requestorThirdParty : null; + + return $this; + } + + public function setStep(string $step): self + { + $this->step = $step; + + return $this; + } + + public function setUser(User $user): self + { + $this->user = $user; + + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php index 6983f6c0e..0dd4a0952 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWork.php @@ -1,13 +1,21 @@ thirdParties = new ArrayCollection(); } + public function addGoal(AccompanyingPeriodWorkGoal $goal): self + { + if (!$this->goals->contains($goal)) { + $this->goals[] = $goal; + $goal->setAccompanyingPeriodWork2($this); + } + + return $this; + } + + public function addResult(Result $result): self + { + if (!$this->results->contains($result)) { + $this->results[] = $result; + } + + return $this; + } + + public function addThirdParty(ThirdParty $thirdParty): self + { + if (!$this->thirdParties->contains($thirdParty)) { + $this->thirdParties[] = $thirdParty; + } + + return $this; + } + + public function getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + public function getCreatedAt(): ?DateTimeInterface + { + return $this->createdAt; + } + + public function getCreatedAutomatically(): ?bool + { + return $this->createdAutomatically; + } + + public function getCreatedAutomaticallyReason(): ?string + { + return $this->createdAutomaticallyReason; + } + + public function getCreatedBy(): ?User + { + return $this->createdBy; + } + + public function getEndDate(): ?DateTimeInterface + { + return $this->endDate; + } + + /** + * @return AccompanyingPeriodWorkGoal[]|Collection + */ + public function getGoals(): Collection + { + return $this->goals; + } + + public function getHandlingThierParty(): ?ThirdParty + { + return $this->handlingThierParty; + } + public function getId(): ?int { return $this->id; @@ -114,23 +193,12 @@ use Doctrine\ORM\Mapping as ORM; return $this->note; } - public function setNote(string $note): self + /** + * @return Collection|Result[] + */ + public function getResults(): Collection { - $this->note = $note; - - return $this; - } - - public function getAccompanyingPeriod(): ?AccompanyingPeriod - { - return $this->accompanyingPeriod; - } - - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self - { - $this->accompanyingPeriod = $accompanyingPeriod; - - return $this; + return $this->results; } public function getSocialAction(): ?SocialAction @@ -138,113 +206,17 @@ use Doctrine\ORM\Mapping as ORM; return $this->socialAction; } - public function setSocialAction(?SocialAction $socialAction): self - { - $this->socialAction = $socialAction; - - return $this; - } - - public function getCreatedAt(): ?\DateTimeInterface - { - return $this->createdAt; - } - - public function setCreatedAt(\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; - - return $this; - } - - public function getCreatedBy(): ?User - { - return $this->createdBy; - } - - public function setCreatedBy(?User $createdBy): self - { - $this->createdBy = $createdBy; - - return $this; - } - - public function getStartDate(): ?\DateTimeInterface + public function getStartDate(): ?DateTimeInterface { return $this->startDate; } - public function setStartDate(\DateTimeInterface $startDate): self - { - $this->startDate = $startDate; - - return $this; - } - - public function getEndDate(): ?\DateTimeInterface - { - return $this->endDate; - } - - public function setEndDate(\DateTimeInterface $endDate): self - { - $this->endDate = $endDate; - - return $this; - } - - public function getHandlingThierParty(): ?ThirdParty - { - return $this->handlingThierParty; - } - - public function setHandlingThierParty(?ThirdParty $handlingThierParty): self - { - $this->handlingThierParty = $handlingThierParty; - - return $this; - } - - public function getCreatedAutomatically(): ?bool - { - return $this->createdAutomatically; - } - - public function setCreatedAutomatically(bool $createdAutomatically): self - { - $this->createdAutomatically = $createdAutomatically; - - return $this; - } - - public function getCreatedAutomaticallyReason(): ?string - { - return $this->createdAutomaticallyReason; - } - - public function setCreatedAutomaticallyReason(string $createdAutomaticallyReason): self - { - $this->createdAutomaticallyReason = $createdAutomaticallyReason; - - return $this; - } - /** - * @return Collection|AccompanyingPeriodWorkGoal[] + * @return Collection|ThirdParty[] */ - public function getGoals(): Collection + public function getThirdParties(): Collection { - return $this->goals; - } - - public function addGoal(AccompanyingPeriodWorkGoal $goal): self - { - if (!$this->goals->contains($goal)) { - $this->goals[] = $goal; - $goal->setAccompanyingPeriodWork2($this); - } - - return $this; + return $this->thirdParties; } public function removeGoal(AccompanyingPeriodWorkGoal $goal): self @@ -259,23 +231,6 @@ use Doctrine\ORM\Mapping as ORM; return $this; } - /** - * @return Collection|Result[] - */ - public function getResults(): Collection - { - return $this->results; - } - - public function addResult(Result $result): self - { - if (!$this->results->contains($result)) { - $this->results[] = $result; - } - - return $this; - } - public function removeResult(Result $result): self { $this->results->removeElement($result); @@ -283,27 +238,80 @@ use Doctrine\ORM\Mapping as ORM; return $this; } - /** - * @return Collection|ThirdParty[] - */ - public function getThirdParties(): Collection - { - return $this->thirdParties; - } - - public function addThirdParty(ThirdParty $thirdParty): self - { - if (!$this->thirdParties->contains($thirdParty)) { - $this->thirdParties[] = $thirdParty; - } - - return $this; - } - public function removeThirdParty(ThirdParty $thirdParty): self { $this->thirdParties->removeElement($thirdParty); return $this; } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; + } + + public function setCreatedAt(DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; + } + + public function setCreatedAutomatically(bool $createdAutomatically): self + { + $this->createdAutomatically = $createdAutomatically; + + return $this; + } + + public function setCreatedAutomaticallyReason(string $createdAutomaticallyReason): self + { + $this->createdAutomaticallyReason = $createdAutomaticallyReason; + + return $this; + } + + public function setCreatedBy(?User $createdBy): self + { + $this->createdBy = $createdBy; + + return $this; + } + + public function setEndDate(DateTimeInterface $endDate): self + { + $this->endDate = $endDate; + + return $this; + } + + public function setHandlingThierParty(?ThirdParty $handlingThierParty): self + { + $this->handlingThierParty = $handlingThierParty; + + return $this; + } + + public function setNote(string $note): self + { + $this->note = $note; + + return $this; + } + + public function setSocialAction(?SocialAction $socialAction): self + { + $this->socialAction = $socialAction; + + return $this; + } + + public function setStartDate(DateTimeInterface $startDate): self + { + $this->startDate = $startDate; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php index ec371d6c2..d34c550c3 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php @@ -1,5 +1,12 @@ results = new ArrayCollection(); } + public function addResult(Result $result): self + { + if (!$this->results->contains($result)) { + $this->results[] = $result; + } + + return $this; + } + + public function getAccompanyingPeriodWork(): ?AccompanyingPeriodWork + { + return $this->accompanyingPeriodWork; + } + + public function getGoal(): ?Goal + { + return $this->goal; + } + public function getId(): ?int { return $this->id; @@ -58,16 +84,19 @@ class AccompanyingPeriodWorkGoal return $this->note; } - public function setNote(string $note): self + /** + * @return Collection|Result[] + */ + public function getResults(): Collection { - $this->note = $note; - - return $this; + return $this->results; } - public function getAccompanyingPeriodWork(): ?AccompanyingPeriodWork + public function removeResult(Result $result): self { - return $this->accompanyingPeriodWork; + $this->results->removeElement($result); + + return $this; } public function setAccompanyingPeriodWork(?AccompanyingPeriodWork $accompanyingPeriodWork): self @@ -77,11 +106,6 @@ class AccompanyingPeriodWorkGoal return $this; } - public function getGoal(): ?Goal - { - return $this->goal; - } - public function setGoal(?Goal $goal): self { $this->goal = $goal; @@ -89,26 +113,9 @@ class AccompanyingPeriodWorkGoal return $this; } - /** - * @return Collection|Result[] - */ - public function getResults(): Collection + public function setNote(string $note): self { - return $this->results; - } - - public function addResult(Result $result): self - { - if (!$this->results->contains($result)) { - $this->results[] = $result; - } - - return $this; - } - - public function removeResult(Result $result): self - { - $this->results->removeElement($result); + $this->note = $note; return $this; } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php index 4e334b2aa..10b3a220d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/ClosingMotive.php @@ -1,42 +1,47 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; /** - * ClosingMotive give an explanation why we closed the Accompanying period + * ClosingMotive give an explanation why we closed the Accompanying period. * * @ORM\Entity( - * repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository") + * repositoryClass="Chill\PersonBundle\Repository\AccompanyingPeriod\ClosingMotiveRepository") * @ORM\Table(name="chill_person_accompanying_period_closingmotive") */ class ClosingMotive { /** - * @var integer + * @var bool + * + * @ORM\Column(type="boolean") + */ + private $active = true; + + /** + * Child Accompanying periods. + * + * @var Collection + * + * @ORM\OneToMany( + * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive", + * mappedBy="parent") + */ + private $children; + + /** + * @var int * * @ORM\Id * @ORM\Column(name="id", type="integer") @@ -50,41 +55,23 @@ class ClosingMotive * @ORM\Column(type="json") */ private $name; - - /** - * @var boolean - * - * @ORM\Column(type="boolean") - */ - private $active = true; - - /** - * @var self - * - * @ORM\ManyToOne( - * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive", - * inversedBy="children") - */ - private $parent = null; - - /** - * Child Accompanying periods - * @var Collection - * - * @ORM\OneToMany( - * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive", - * mappedBy="parent") - */ - private $children; - + /** * @var float * * @ORM\Column(type="float") */ private $ordering = 0.0; - - + + /** + * @var self + * + * @ORM\ManyToOne( + * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive", + * inversedBy="children") + */ + private $parent; + /** * ClosingMotive constructor. */ @@ -92,11 +79,28 @@ class ClosingMotive { $this->children = new ArrayCollection(); } - + + public function addChildren(ClosingMotive $child): ClosingMotive + { + if ($this->children->contains($child)) { + return $this; + } + + $this->children->add($child); + $child->setParent($this); + + return $this; + } + + public function getChildren(): Collection + { + return $this->children; + } + /** - * Get id + * Get id. * - * @return integer + * @return int */ public function getId() { @@ -104,7 +108,87 @@ class ClosingMotive } /** - * Set name + * Get name. + * + * @return array + */ + public function getName() + { + return $this->name; + } + + public function getOrdering(): float + { + return $this->ordering; + } + + /** + * @return ClosingMotive + */ + public function getParent() + { + return $this->parent; + } + + public function hasParent(): bool + { + return null !== $this->parent; + } + + public function isActive(): bool + { + return $this->active; + } + + public function isChild(): bool + { + return null !== $this->parent; + } + + public function isLeaf(): bool + { + return $this->children->count() === 0; + } + + public function isParent(): bool + { + return $this->children->count() > 0; + } + + public function removeChildren(ClosingMotive $child): ClosingMotive + { + if ($this->children->removeElement($child)) { + $child->setParent(null); + } + + return $this; + } + + /** + * @return $this + */ + public function setActive(bool $active) + { + $this->active = $active; + + if (false === $this->active) { + foreach ($this->getChildren() as $child) { + $child->setActive(false); + } + } + + return $this; + } + + public function setChildren(Collection $children): ClosingMotive + { + $this->children = $children; + + return $this; + } + + /** + * Set name. * * @param array $name * @@ -118,161 +202,23 @@ class ClosingMotive } /** - * Get name - * - * @return array - */ - public function getName() - { - return $this->name; - } - - /** - * @return bool - */ - public function isActive(): bool - { - return $this->active; - } - - /** - * @param bool $active - * @return $this - */ - public function setActive(bool $active) - { - $this->active = $active; - - if ($this->active === FALSE) { - foreach ($this->getChildren() as $child) { - $child->setActive(FALSE); - } - } - - return $this; - } - - /** - * @return ClosingMotive - */ - public function getParent() - { - return $this->parent; - } - - /** - * @return Collection - */ - public function getChildren(): Collection - { - return $this->children; - } - - /** - * @param ClosingMotive|null $parent - * @return ClosingMotive - */ - public function setParent(?ClosingMotive $parent): ClosingMotive - { - $this->parent = $parent; - - if (NULL !== $parent) { - //$parent->addChildren($this); - } - - return $this; - } - - /** - * @param Collection $children - * @return ClosingMotive - */ - public function setChildren(Collection $children): ClosingMotive - { - $this->children = $children; - - return $this; - } - - /** - * @param ClosingMotive $child - * @return ClosingMotive - */ - public function addChildren(ClosingMotive $child): ClosingMotive - { - if ($this->children->contains($child)) { - return $this; - } - - $this->children->add($child); - $child->setParent($this); - - return $this; - } - - /** - * @param ClosingMotive $child - * @return ClosingMotive - */ - public function removeChildren(ClosingMotive $child): ClosingMotive - { - if ($this->children->removeElement($child)) { - $child->setParent(null); - } - - return $this; - } - - /** - * @return float - */ - public function getOrdering(): float - { - return $this->ordering; - } - - /** - * @param float $ordering * @return $this */ public function setOrdering(float $ordering) { $this->ordering = $ordering; - + return $this; } - - /** - * @return bool - */ - public function isChild(): bool - { - return $this->parent !== null; - } - - /** - * @return bool - */ - public function isParent(): bool - { - return $this->children->count() > 0; - } - - /** - * @return bool - */ - public function isLeaf(): bool - { - return $this->children->count() === 0; - } - - /** - * @return bool - */ - public function hasParent(): bool - { - return $this->parent !== null; - } + public function setParent(?ClosingMotive $parent): ClosingMotive + { + $this->parent = $parent; + + if (null !== $parent) { + //$parent->addChildren($this); + } + + return $this; + } } - diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php index e8ecf3248..033fee79d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Comment.php @@ -1,30 +1,18 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Repository\AccompanyingPeriod\CommentRepository; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Repository\AccompanyingPeriod\CommentRepository; +use DateTimeInterface; use Doctrine\ORM\Mapping as ORM; /** @@ -33,21 +21,24 @@ use Doctrine\ORM\Mapping as ORM; */ class Comment { - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ - private $id; - /** * @ORM\ManyToOne( * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", - * inversedBy="comments") + * inversedBy="comments") * @ORM\JoinColumn(nullable=false) */ private $accompanyingPeriod; + /** + * @ORM\Column(type="text") + */ + private $content; + + /** + * @ORM\Column(type="datetime") + */ + private $createdAt; + /** * @ORM\ManyToOne(targetEntity=User::class) * @ORM\JoinColumn(nullable=false) @@ -55,9 +46,11 @@ class Comment private $creator; /** - * @ORM\Column(type="datetime") + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") */ - private $createdAt; + private $id; /** * @ORM\Column(type="datetime") @@ -70,19 +63,39 @@ class Comment */ private $updatedBy; - /** - * @ORM\Column(type="text") - */ - private $content; + public function getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + public function getContent(): ?string + { + return $this->content; + } + + public function getCreatedAt(): ?DateTimeInterface + { + return $this->createdAt; + } + + public function getCreator(): ?User + { + return $this->creator; + } public function getId(): ?int { return $this->id; } - public function getAccompanyingPeriod(): ?AccompanyingPeriod + public function getUpdatedAt(): ?DateTimeInterface { - return $this->accompanyingPeriod; + return $this->updatedAt; + } + + public function getUpdatedBy(): ?User + { + return $this->updatedBy; } public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self @@ -92,9 +105,18 @@ class Comment return $this; } - public function getCreator(): ?User + public function setContent(string $content): self { - return $this->creator; + $this->content = $content; + + return $this; + } + + public function setCreatedAt(DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; } public function setCreator(?User $creator): self @@ -104,51 +126,17 @@ class Comment return $this; } - public function getCreatedAt(): ?\DateTimeInterface - { - return $this->createdAt; - } - - public function setCreatedAt(\DateTimeInterface $createdAt): self - { - $this->createdAt = $createdAt; - - return $this; - } - - public function getUpdatedAt(): ?\DateTimeInterface - { - return $this->updatedAt; - } - - public function setUpdatedAt(\DateTimeInterface $updatedAt): self + public function setUpdatedAt(DateTimeInterface $updatedAt): self { $this->updatedAt = $updatedAt; return $this; } - public function getUpdatedBy(): ?User - { - return $this->updatedBy; - } - public function setUpdatedBy(?User $updatedBy): self { $this->updatedBy = $updatedBy; return $this; } - - public function getContent(): ?string - { - return $this->content; - } - - public function setContent(string $content): self - { - $this->content = $content; - - return $this; - } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php index 55857de4c..71d38fb06 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Origin.php @@ -1,28 +1,16 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Repository\AccompanyingPeriod\OriginRepository; +use DateTimeImmutable; use Doctrine\ORM\Mapping as ORM; /** @@ -58,6 +46,11 @@ class Origin return $this->label; } + public function getNoActiveAfter(): ?DateTimeImmutable + { + return $this->noActiveAfter; + } + public function setLabel(string $label): self { $this->label = $label; @@ -65,12 +58,7 @@ class Origin return $this; } - public function getNoActiveAfter(): ?\DateTimeImmutable - { - return $this->noActiveAfter; - } - - public function setNoActiveAfter(?\DateTimeImmutable $noActiveAfter): self + public function setNoActiveAfter(?DateTimeImmutable $noActiveAfter): self { $this->noActiveAfter = $noActiveAfter; diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php index ec13fcad6..ddd8f9f3d 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php @@ -1,31 +1,17 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Doctrine\ORM\Mapping as ORM; @@ -35,13 +21,6 @@ use Doctrine\ORM\Mapping as ORM; */ class Resource { - /** - * @ORM\Id - * @ORM\GeneratedValue - * @ORM\Column(type="integer") - */ - private $id; - /** * @ORM\ManyToOne( * targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", @@ -52,10 +31,17 @@ class Resource private $accompanyingPeriod; /** - * @ORM\ManyToOne(targetEntity=ThirdParty::class) + * @ORM\ManyToOne(targetEntity=Comment::class) * @ORM\JoinColumn(nullable=true) */ - private $thirdParty; + private $comment; + + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; /** * @ORM\ManyToOne(targetEntity=Person::class) @@ -64,19 +50,42 @@ class Resource private $person; /** - * @ORM\ManyToOne(targetEntity=Comment::class) + * @ORM\ManyToOne(targetEntity=ThirdParty::class) * @ORM\JoinColumn(nullable=true) */ - private $comment; + private $thirdParty; + + public function getAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->accompanyingPeriod; + } + + public function getComment(): ?Comment + { + return $this->comment; + } public function getId(): ?int { return $this->id; } - public function getAccompanyingPeriod(): ?AccompanyingPeriod + public function getPerson(): ?Person { - return $this->accompanyingPeriod; + return $this->person; + } + + /** + * @return Person|ThirdParty + */ + public function getResource() + { + return $this->person ?? $this->thirdParty; + } + + public function getThirdParty(): ?ThirdParty + { + return $this->thirdParty; } public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self @@ -86,23 +95,13 @@ class Resource return $this; } - public function getThirdParty(): ?ThirdParty + public function setComment(?Comment $comment): self { - return $this->thirdParty; - } - - public function setThirdParty(?ThirdParty $thirdParty): self - { - $this->thirdParty = $thirdParty; + $this->comment = $comment; return $this; } - public function getPerson(): ?Person - { - return $this->person; - } - public function setPerson(?Person $person): self { $this->person = $person; @@ -110,23 +109,10 @@ class Resource return $this; } - public function getComment(): ?Comment + public function setThirdParty(?ThirdParty $thirdParty): self { - return $this->comment; - } - - public function setComment(?Comment $comment): self - { - $this->comment = $comment; + $this->thirdParty = $thirdParty; return $this; } - - /** - * @return Person|ThirdParty - */ - public function getResource() - { - return $this->person ?? $this->thirdParty; - } } diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php index c22e84e42..a93f1db2c 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriodParticipation.php @@ -1,124 +1,110 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity; use Chill\PersonBundle\Repository\AccompanyingPeriodParticipationRepository; -use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; +use DateTimeImmutable; +use DateTimeInterface; use Doctrine\ORM\Mapping as ORM; /** - * AccompanyingPeriodParticipation Class + * AccompanyingPeriodParticipation Class. * - * @package Chill\PersonBundle\Entity * @ORM\Entity(repositoryClass=AccompanyingPeriodParticipationRepository::class) * @ORM\Table(name="chill_person_accompanying_period_participation") */ class AccompanyingPeriodParticipation { + /** + * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"}) + * @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false) + */ + private $accompanyingPeriod; + + /** + * @ORM\Column(type="date", nullable=true) + */ + private $endDate; + /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private $id; - + /** * @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodParticipations") * @ORM\JoinColumn(name="person_id", referencedColumnName="id", nullable=false) */ private $person; - - /** - * @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class, inversedBy="participations", cascade={"persist"}) - * @ORM\JoinColumn(name="accompanyingperiod_id", referencedColumnName="id", nullable=false) - */ - private $accompanyingPeriod; - + /** * @ORM\Column(type="date", nullable=false) */ private $startDate; - - /** - * @ORM\Column(type="date", nullable=true) - */ - private $endDate = null; - + public function __construct(AccompanyingPeriod $accompanyingPeriod, Person $person) { - $this->startDate = new \DateTimeImmutable('now'); + $this->startDate = new DateTimeImmutable('now'); $this->accompanyingPeriod = $accompanyingPeriod; $this->person = $person; } - - public function getId(): ?int - { - return $this->id; - } - - public function getPerson(): ?Person - { - return $this->person; - } - - public function setPerson(?Person $person): self - { - $this->person = $person; - - return $this; - } - + public function getAccompanyingPeriod(): ?AccompanyingPeriod { return $this->accompanyingPeriod; } - - public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self - { - $this->accompanyingPeriod = $accompanyingPeriod; - - return $this; - } - - public function getStartDate(): ?\DateTimeInterface - { - return $this->startDate; - } - + /* * public function setStartDate(\DateTimeInterface $startDate): self { $this->startDate = $startDate; return $this; } */ - - public function getEndDate(): ?\DateTimeInterface + + public function getEndDate(): ?DateTimeInterface { return $this->endDate; } - - public function setEndDate(?\DateTimeInterface $endDate): self + + public function getId(): ?int + { + return $this->id; + } + + public function getPerson(): ?Person + { + return $this->person; + } + + public function getStartDate(): ?DateTimeInterface + { + return $this->startDate; + } + + public function setAccompanyingPeriod(?AccompanyingPeriod $accompanyingPeriod): self + { + $this->accompanyingPeriod = $accompanyingPeriod; + + return $this; + } + + public function setEndDate(?DateTimeInterface $endDate): self { $this->endDate = $endDate; - + + return $this; + } + + public function setPerson(?Person $person): self + { + $this->person = $person; + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/HasPerson.php b/src/Bundle/ChillPersonBundle/Entity/HasPerson.php index e200182bc..97b170009 100644 --- a/src/Bundle/ChillPersonBundle/Entity/HasPerson.php +++ b/src/Bundle/ChillPersonBundle/Entity/HasPerson.php @@ -1,34 +1,20 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\PersonBundle\Entity; - -use Chill\PersonBundle\Entity\Person; /** - * Interface which applies to entities which are associated to a single person - * + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\PersonBundle\Entity; + +/** + * Interface which applies to entities which are associated to a single person. */ interface HasPerson { - public function setPerson(Person $person = null): HasPerson; - public function getPerson(): ?Person; + + public function setPerson(?Person $person = null): HasPerson; } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php index a12741dee..f18c03461 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php @@ -1,17 +1,37 @@ id; - } - /** - * Addresses - * @var Collection - * - * @ORM\ManyToMany( - * targetEntity="Chill\MainBundle\Entity\Address", - * cascade={"persist", "remove", "merge", "detach"}) - * @ORM\JoinTable(name="chill_person_household_to_addresses") - * @ORM\OrderBy({"validFrom" = "DESC"}) - */ - private $addresses; - - - /** - * @param Address $address * @return $this */ public function addAddress(Address $address) @@ -48,17 +49,9 @@ class Household return $this; } - /** - * @param Address $address - */ - public function removeAddress(Address $address) - { - $this->addresses->removeElement($address); - } - /** * By default, the addresses are ordered by date, descending (the most - * recent first) + * recent first). * * @return \Chill\MainBundle\Entity\Address[] */ @@ -67,4 +60,13 @@ class Household return $this->addresses; } + public function getId(): ?int + { + return $this->id; + } + + public function removeAddress(Address $address) + { + $this->addresses->removeElement($address); + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMembers.php b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMembers.php index 80864ecd0..2ef92fc19 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMembers.php +++ b/src/Bundle/ChillPersonBundle/Entity/Household/HouseholdMembers.php @@ -1,17 +1,42 @@ comment; + } + + public function getEndDate(): ?DateTimeInterface + { + return $this->endDate; + } + + public function getHousehold(): ?Household + { + return $this->household; + } public function getId(): ?int { return $this->id; } + public function getPerson(): ?Person + { + return $this->person; + } + public function getPosition(): ?string { return $this->position; } - public function setPosition(?string $position): self + public function getSharedHousehold(): ?bool { - $this->position = $position; - - return $this; + return $this->sharedHousehold; } - public function getStartDate(): ?\DateTimeInterface + public function getStartDate(): ?DateTimeInterface { return $this->startDate; } - public function setStartDate(\DateTimeInterface $startDate): self - { - $this->startDate = $startDate; - - return $this; - } - - public function getEndDate(): ?\DateTimeInterface - { - return $this->endDate; - } - - public function setEndDate(\DateTimeInterface $endDate): self - { - $this->endDate = $endDate; - - return $this; - } - - public function getComment(): ?string - { - return $this->comment; - } - public function setComment(?string $comment): self { $this->comment = $comment; @@ -115,21 +114,18 @@ class HouseholdMembers return $this; } - public function getSharedHousehold(): ?bool + public function setEndDate(DateTimeInterface $endDate): self { - return $this->sharedHousehold; - } - - public function setSharedHousehold(bool $sharedHousehold): self - { - $this->sharedHousehold = $sharedHousehold; + $this->endDate = $endDate; return $this; } - public function getPerson(): ?Person + public function setHousehold(?Household $household): self { - return $this->person; + $this->household = $household; + + return $this; } public function setPerson(?Person $person): self @@ -139,14 +135,23 @@ class HouseholdMembers return $this; } - public function getHousehold(): ?Household + public function setPosition(?string $position): self { - return $this->household; + $this->position = $position; + + return $this; } - public function setHousehold(?Household $household): self + public function setSharedHousehold(bool $sharedHousehold): self { - $this->household = $household; + $this->sharedHousehold = $sharedHousehold; + + return $this; + } + + public function setStartDate(DateTimeInterface $startDate): self + { + $this->startDate = $startDate; return $this; } diff --git a/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php b/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php index f1addbb2c..2bb09d60c 100644 --- a/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php +++ b/src/Bundle/ChillPersonBundle/Entity/MaritalStatus.php @@ -1,21 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Entity; @@ -23,18 +12,18 @@ namespace Chill\PersonBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** - * MaritalStatus + * MaritalStatus. * - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="chill_person_marital_status") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class MaritalStatus { /** * @var string * - * @ORM\Id() + * @ORM\Id * @ORM\Column(type="string", length=7) */ private $id; @@ -46,9 +35,9 @@ class MaritalStatus private $name; /** - * Get id + * Get id. * - * @return string + * @return string */ public function getId() { @@ -56,37 +45,40 @@ class MaritalStatus } /** - * Set id - * + * Get name. + * + * @return string array + */ + public function getName() + { + return $this->name; + } + + /** + * Set id. + * * @param string $id + * * @return MaritalStatus */ public function setId($id) { $this->id = $id; + return $this; } /** - * Set name + * Set name. * * @param string array $name + * * @return MaritalStatus */ public function setName($name) { $this->name = $name; - + return $this; } - - /** - * Get name - * - * @return string array - */ - public function getName() - { - return $this->name; - } } diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php index 3624d4c17..1d3425133 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Person.php +++ b/src/Bundle/ChillPersonBundle/Entity/Person.php @@ -1,5 +1,12 @@ accompanyingPeriodParticipations = new ArrayCollection(); $this->spokenLanguages = new ArrayCollection(); @@ -281,38 +313,23 @@ class Person implements HasCenterInterface $this->altNames = new ArrayCollection(); $this->otherPhoneNumbers = new ArrayCollection(); - if ($opening === null) { - $opening = new \DateTime(); + if (null === $opening) { + $opening = new DateTime(); } $this->open(new AccompanyingPeriod($opening)); } - + /** - * This private function scan accompanyingPeriodParticipations Collection, - * searching for a given AccompanyingPeriod + * @return string */ - private function participationsContainAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): ?AccompanyingPeriodParticipation + public function __toString() { - foreach ($this->accompanyingPeriodParticipations as $participation) { - /** @var AccompanyingPeriodParticipation $participation */ - if ($accompanyingPeriod === $participation->getAccompanyingPeriod()) { - return $participation; - }} - - return null; + return $this->getLabel(); } - + /** - * This public function is the same but return only true or false - */ - public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool - { - return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true; - } - - /** - * Add AccompanyingPeriodParticipation + * Add AccompanyingPeriodParticipation. * * @uses AccompanyingPeriod::addPerson */ @@ -320,37 +337,88 @@ class Person implements HasCenterInterface { $participation = new AccompanyingPeriodParticipation($accompanyingPeriod, $this); $this->accompanyingPeriodParticipations->add($participation); - + return $this; } /** - * Remove AccompanyingPeriod + * @return $this */ - public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod) : void + public function addAddress(Address $address) { - $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod); - - if (! null === $participation) { - $participation->setEndDate(\DateTimeImmutable::class); - $this->accompanyingPeriodParticipations->removeElement($participation); - } + $this->addresses[] = $address; + + return $this; } /** - * set the Person file as open at the given date. - * - * For updating a opening's date, you should update AccompanyingPeriod instance - * directly. - * - * For closing a file, @see this::close - * - * To check if the Person and its accompanying period is consistent, use validation. + * @return $this */ - public function open(AccompanyingPeriod $accompanyingPeriod) : void + public function addAltName(PersonAltName $altName) { - $this->proxyAccompanyingPeriodOpenState = true; - $this->addAccompanyingPeriod($accompanyingPeriod); + if (false === $this->altNames->contains($altName)) { + $this->altNames->add($altName); + $altName->setPerson($this); + } + + return $this; + } + + /** + * @return $this + */ + public function addOtherPhoneNumber(PersonPhone $otherPhoneNumber) + { + if (false === $this->otherPhoneNumbers->contains($otherPhoneNumber)) { + $otherPhoneNumber->setPerson($this); + $this->otherPhoneNumbers->add($otherPhoneNumber); + } + + return $this; + } + + // a period opened and another one after it + + /** + * Function used for validation that check if the accompanying periods of + * the person are not collapsing (i.e. have not shared days) or having + * a period after an open period. + * + * @return true | array True if the accompanying periods are not collapsing, + * an array with data for displaying the error + */ + public function checkAccompanyingPeriodsAreNotCollapsing() + { + $periods = $this->getAccompanyingPeriodsOrdered(); + $periodsNbr = sizeof($periods); + $i = 0; + + while ($periodsNbr - 1 > $i) { + $periodI = $periods[$i]; + $periodAfterI = $periods[$i + 1]; + + if ($periodI->isOpen()) { + return [ + 'result' => self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD, + 'dateOpening' => $periodAfterI->getOpeningDate(), + 'dateClosing' => $periodAfterI->getClosingDate(), + 'date' => $periodI->getOpeningDate(), + ]; + } + + if ($periodI->getClosingDate() >= $periodAfterI->getOpeningDate()) { + return [ + 'result' => self::ERROR_PERIODS_ARE_COLLAPSING, + 'dateOpening' => $periodI->getOpeningDate(), + + 'dateClosing' => $periodI->getClosingDate(), + 'date' => $periodAfterI->getOpeningDate(), + ]; + } + ++$i; + } + + return true; } /** @@ -361,62 +429,44 @@ class Person implements HasCenterInterface * * To check if the Person and its accompanying period are consistent, use validation. * - * @throws \Exception if two lines of the accompanying period are open. + * @throws Exception if two lines of the accompanying period are open. */ - public function close(AccompanyingPeriod $accompanyingPeriod = null) : void + public function close(?AccompanyingPeriod $accompanyingPeriod = null): void { $this->proxyAccompanyingPeriodOpenState = false; } /** - * Return the opened accompanying period. + * This public function is the same but return only true or false. */ - public function getOpenedAccompanyingPeriod() : ?AccompanyingPeriod + public function containsAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): bool { - if ($this->isOpen() === false) { - return null; - } - - foreach ($this->accompanyingPeriodParticipations as $participation) { - /** @var AccompanyingPeriodParticipation $participation */ - if ($participation->getAccompanyingPeriod()->isOpen()) { - return $participation->getAccompanyingPeriod(); - } - } + return ($this->participationsContainAccompanyingPeriod($accompanyingPeriod)) ? false : true; } /** - * Returns the opened accompanying period. - * - * @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead - */ - public function getCurrentAccompanyingPeriod() : ?AccompanyingPeriod - { - return $this->getOpenedAccompanyingPeriod(); - } - - /** - * Get AccompanyingPeriods array - */ - public function getAccompanyingPeriods(): array - { - $accompanyingPeriods = []; - foreach ($this->accompanyingPeriodParticipations as $participation) - { - /** @var AccompanyingPeriodParticipation $participation */ - $accompanyingPeriods[] = $participation->getAccompanyingPeriod(); - } - return $accompanyingPeriods; - } - - /** - * Get AccompanyingPeriodParticipations Collection + * Get AccompanyingPeriodParticipations Collection. */ public function getAccompanyingPeriodParticipations(): Collection { return $this->accompanyingPeriodParticipations; } + /** + * Get AccompanyingPeriods array. + */ + public function getAccompanyingPeriods(): array + { + $accompanyingPeriods = []; + + foreach ($this->accompanyingPeriodParticipations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + $accompanyingPeriods[] = $participation->getAccompanyingPeriod(); + } + + return $accompanyingPeriods; + } + /** * Get the accompanying periods of a give person with the chronological order. */ @@ -425,7 +475,7 @@ class Person implements HasCenterInterface $periods = $this->getAccompanyingPeriods(); //order by date : - usort($periods, function($a, $b) { + usort($periods, function ($a, $b) { $dateA = $a->getOpeningDate(); $dateB = $b->getOpeningDate(); @@ -439,60 +489,111 @@ class Person implements HasCenterInterface if ($dateEA < $dateEB) { return -1; - } else { - return +1; } + + return +1; } if ($dateA < $dateB) { - return -1 ; - } else { - return 1; + return -1; } + + return 1; }); return $periods; } /** - * Check if the person is opened + * By default, the addresses are ordered by date, descending (the most + * recent first). */ - public function isOpen() : bool + public function getAddresses(): Collection { - foreach ($this->getAccompanyingPeriods() as $period) { - if ($period->isOpen()) { - return true; - } + return $this->addresses; + } + + public function getAltNames(): Collection + { + return $this->altNames; + } + + /** + * Get birthdate. + * + * @return DateTime + */ + public function getBirthdate() + { + return $this->birthdate; + } + + /** + * Get center. + * + * @return Center + */ + public function getCenter() + { + return $this->center; + } + + /** + * Get cFData. + * + * @return array + */ + public function getCFData() + { + if (null === $this->cFData) { + $this->cFData = []; } - return false; + return $this->cFData; } /** - * Get id + * Get contactInfo. * - * @return integer + * @return string */ - public function getId() + public function getcontactInfo() { - return $this->id; + return $this->contactInfo; } /** - * Set firstName + * Get countryOfBirth. * - * @param string $firstName - * @return Person + * @return Chill\MainBundle\Entity\Country */ - public function setFirstName($firstName) + public function getCountryOfBirth() { - $this->firstName = $firstName; - - return $this; + return $this->countryOfBirth; } /** - * Get firstName + * Returns the opened accompanying period. + * + * @deprecated since 1.1 use `getOpenedAccompanyingPeriod instead + */ + public function getCurrentAccompanyingPeriod(): ?AccompanyingPeriod + { + return $this->getOpenedAccompanyingPeriod(); + } + + /** + * Get email. + * + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * Get firstName. * * @return string */ @@ -501,141 +602,13 @@ class Person implements HasCenterInterface return $this->firstName; } - /** - * Set lastName - * - * @param string $lastName - * @return Person - */ - public function setLastName($lastName) + public function getFullnameCanonical(): string { - $this->lastName = $lastName; - - return $this; + return $this->fullnameCanonical; } /** - * Get lastName - * - * @return string - */ - public function getLastName() - { - return $this->lastName; - } - - /** - * @return Collection - */ - public function getAltNames(): Collection - { - return $this->altNames; - } - - /** - * @param Collection $altNames - * @return $this - */ - public function setAltNames(Collection $altNames) - { - $this->altNames = $altNames; - - return $this; - } - - /** - * @param PersonAltName $altName - * @return $this - */ - public function addAltName(PersonAltName $altName) - { - if (FALSE === $this->altNames->contains($altName)) { - $this->altNames->add($altName); - $altName->setPerson($this); - } - - return $this; - } - - /** - * @param PersonAltName $altName - * @return $this - */ - public function removeAltName(PersonAltName $altName) - { - if ($this->altNames->contains($altName)) { - $altName->setPerson(null); - $this->altNames->removeElement($altName); - } - - return $this; - } - - /** - * Set birthdate - * - * @param \DateTime $birthdate - * @return Person - */ - public function setBirthdate($birthdate) - { - $this->birthdate = $birthdate; - - return $this; - } - - /** - * Get birthdate - * - * @return \DateTime - */ - public function getBirthdate() - { - return $this->birthdate; - } - - /** - * Set placeOfBirth - * - * @param string $placeOfBirth - * @return Person - */ - public function setPlaceOfBirth($placeOfBirth) - { - if ($placeOfBirth === null) { - $placeOfBirth = ''; - } - - $this->placeOfBirth = $placeOfBirth; - - return $this; - } - - /** - * Get placeOfBirth - * - * @return string - */ - public function getPlaceOfBirth() - { - return $this->placeOfBirth; - } - - /** - * Set gender - * - * @param string $gender - * @return Person - */ - public function setGender($gender) - { - $this->gender = $gender; - - return $this; - } - - /** - * Get gender + * Get gender. * * @return string */ @@ -646,166 +619,27 @@ class Person implements HasCenterInterface /** * return gender as a Numeric form. - * This is used for translations + * This is used for translations. + * * @return int */ public function getGenderNumeric() { if ($this->getGender() == self::FEMALE_GENDER) { return 1; - } else { - return 0; - } - } - - /** - * Set memo - * - * @param string $memo - * @return Person - */ - public function setMemo($memo) - { - if ($memo === null) { - $memo = ''; } - if ($this->memo !== $memo) { - $this->memo = $memo; - } - - return $this; + return 0; } /** - * Get memo + * Get id. * - * @return string + * @return int */ - public function getMemo() + public function getId() { - return $this->memo; - } - - /** - * Set maritalStatus - * - * @param MaritalStatus $maritalStatus - * @return Person - */ - public function setMaritalStatus(MaritalStatus $maritalStatus = null) - { - $this->maritalStatus = $maritalStatus; - return $this; - } - - /** - * Get maritalStatus - * - * @return MaritalStatus - */ - public function getMaritalStatus() - { - return $this->maritalStatus; - } - - /** - * Set contactInfo - * - * @param string $contactInfo - * @return Person - */ - public function setcontactInfo($contactInfo) - { - if ($contactInfo === null) { - $contactInfo = ''; - } - - $this->contactInfo = $contactInfo; - - return $this; - } - - /** - * Get contactInfo - * - * @return string - */ - public function getcontactInfo() - { - return $this->contactInfo; - } - - /** - * Set email - * - * @param string $email - * @return Person - */ - public function setEmail($email) - { - if ($email === null) { - $email = ''; - } - - $this->email = $email; - - return $this; - } - - /** - * Get email - * - * @return string - */ - public function getEmail() - { - return $this->email; - } - - /** - * Set countryOfBirth - * - * @param Chill\MainBundle\Entity\Country $countryOfBirth - * @return Person - */ - public function setCountryOfBirth(Country $countryOfBirth = null) - { - $this->countryOfBirth = $countryOfBirth; - return $this; - } - - /** - * Get countryOfBirth - * - * @return Chill\MainBundle\Entity\Country - */ - public function getCountryOfBirth() - { - return $this->countryOfBirth; - } - - /** - * Set nationality - * - * @param Chill\MainBundle\Entity\Country $nationality - * @return Person - */ - public function setNationality(Country $nationality = null) - { - $this->nationality = $nationality; - - return $this; - } - - /** - * Get nationality - * - * @return Chill\MainBundle\Entity\Country - */ - public function getNationality() - { - return $this->nationality; + return $this->id; } /** @@ -813,210 +647,10 @@ class Person implements HasCenterInterface */ public function getLabel() { - return $this->getFirstName()." ".$this->getLastName(); + return $this->getFirstName() . ' ' . $this->getLastName(); } - /** - * Get center - * - * @return Center - */ - public function getCenter() - { - return $this->center; - } - - /** - * Set the center - * - * @param Center $center - * @return \Chill\PersonBundle\Entity\Person - */ - public function setCenter(Center $center) - { - $this->center = $center; - return $this; - } - - /** - * Set cFData - * - * @param array $cFData - * - * @return Report - */ - public function setCFData($cFData) - { - $this->cFData = $cFData; - - return $this; - } - - /** - * Get cFData - * - * @return array - */ - public function getCFData() - { - if ($this->cFData === null) { - $this->cFData = []; - } - return $this->cFData; - } - - /** - * Set phonenumber - * - * @param string $phonenumber - * @return Person - */ - public function setPhonenumber($phonenumber = '') - { - $this->phonenumber = $phonenumber; - - return $this; - } - - /** - * Get phonenumber - * - * @return string - */ - public function getPhonenumber() - { - return $this->phonenumber; - } - - /** - * Set mobilenumber - * - * @param string $mobilenumber - * @return Person - */ - public function setMobilenumber($mobilenumber = '') - { - $this->mobilenumber = $mobilenumber; - - return $this; - } - - /** - * Get mobilenumber - * - * @return string - */ - public function getMobilenumber() - { - return $this->mobilenumber; - } - - /** - * @return Collection - */ - public function getOtherPhoneNumbers(): Collection - { - return $this->otherPhoneNumbers; - } - - /** - * @param Collection $otherPhoneNumbers - * @return $this - */ - public function setOtherPhoneNumbers(Collection $otherPhoneNumbers) - { - $this->otherPhoneNumbers = $otherPhoneNumbers; - - return $this; - } - - /** - * @param PersonPhone $otherPhoneNumber - * @return $this - */ - public function addOtherPhoneNumber(PersonPhone $otherPhoneNumber) - { - if (false === $this->otherPhoneNumbers->contains($otherPhoneNumber)) { - $otherPhoneNumber->setPerson($this); - $this->otherPhoneNumbers->add($otherPhoneNumber); - } - - return $this; - } - - /** - * @param PersonPhone $otherPhoneNumber - * @return $this - */ - public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber) - { - if ($this->otherPhoneNumbers->contains($otherPhoneNumber)) { - $this->otherPhoneNumbers->removeElement($otherPhoneNumber); - } - - return $this; - } - - /** - * @return string - */ - public function __toString() - { - return $this->getLabel(); - } - - /** - * Set spokenLanguages - * - * @param type $spokenLanguages - * @return Person - */ - public function setSpokenLanguages($spokenLanguages) - { - $this->spokenLanguages = $spokenLanguages; - - return $this; - } - - /** - * Get spokenLanguages - * - * @return ArrayCollection - */ - public function getSpokenLanguages() - { - return $this->spokenLanguages; - } - - /** - * @param Address $address - * @return $this - */ - public function addAddress(Address $address) - { - $this->addresses[] = $address; - - return $this; - } - - /** - * @param Address $address - */ - public function removeAddress(Address $address) - { - $this->addresses->removeElement($address); - } - - /** - * By default, the addresses are ordered by date, descending (the most - * recent first) - */ - public function getAddresses(): Collection - { - return $this->addresses; - } - - public function getLastAddress(DateTime $from = null) + public function getLastAddress(?DateTime $from = null) { $from ??= new DateTime('now'); @@ -1035,36 +669,114 @@ class Person implements HasCenterInterface } /** - * Validation callback that checks if the accompanying periods are valid + * Get lastName. * - * This method add violation errors. + * @return string */ - public function isAccompanyingPeriodValid(ExecutionContextInterface $context) + public function getLastName() { - $r = $this->checkAccompanyingPeriodsAreNotCollapsing(); + return $this->lastName; + } - if ($r !== true) { - if ($r['result'] === self::ERROR_PERIODS_ARE_COLLAPSING) { - $context->buildViolation('Two accompanying periods have days in commun') - ->atPath('accompanyingPeriods') - ->addViolation(); - } + /** + * Get maritalStatus. + * + * @return MaritalStatus + */ + public function getMaritalStatus() + { + return $this->maritalStatus; + } - if ($r['result'] === self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD) { - $context->buildViolation('A period is opened and a period is added after it') - ->atPath('accompanyingPeriods') - ->addViolation(); + /** + * Get memo. + * + * @return string + */ + public function getMemo() + { + return $this->memo; + } + + /** + * Get mobilenumber. + * + * @return string + */ + public function getMobilenumber() + { + return $this->mobilenumber; + } + + /** + * Get nationality. + * + * @return Chill\MainBundle\Entity\Country + */ + public function getNationality() + { + return $this->nationality; + } + + /** + * Return the opened accompanying period. + */ + public function getOpenedAccompanyingPeriod(): ?AccompanyingPeriod + { + if ($this->isOpen() === false) { + return null; + } + + foreach ($this->accompanyingPeriodParticipations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + if ($participation->getAccompanyingPeriod()->isOpen()) { + return $participation->getAccompanyingPeriod(); } } } + public function getOtherPhoneNumbers(): Collection + { + return $this->otherPhoneNumbers; + } + + /** + * Get phonenumber. + * + * @return string + */ + public function getPhonenumber() + { + return $this->phonenumber; + } + + /** + * Get placeOfBirth. + * + * @return string + */ + public function getPlaceOfBirth() + { + return $this->placeOfBirth; + } + + /** + * Get spokenLanguages. + * + * @return ArrayCollection + */ + public function getSpokenLanguages() + { + return $this->spokenLanguages; + } + /** * Return true if the person has two addresses with the - * same validFrom date (in format 'Y-m-d') + * same validFrom date (in format 'Y-m-d'). */ public function hasTwoAdressWithSameValidFromDate() { - $validYMDDates = array(); + $validYMDDates = []; foreach ($this->addresses as $ad) { $validDate = $ad->getValidFrom()->format('Y-m-d'); @@ -1078,9 +790,33 @@ class Person implements HasCenterInterface return false; } + /** + * Validation callback that checks if the accompanying periods are valid. + * + * This method add violation errors. + */ + public function isAccompanyingPeriodValid(ExecutionContextInterface $context) + { + $r = $this->checkAccompanyingPeriodsAreNotCollapsing(); + + if (true !== $r) { + if (self::ERROR_PERIODS_ARE_COLLAPSING === $r['result']) { + $context->buildViolation('Two accompanying periods have days in commun') + ->atPath('accompanyingPeriods') + ->addViolation(); + } + + if (self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD === $r['result']) { + $context->buildViolation('A period is opened and a period is added after it') + ->atPath('accompanyingPeriods') + ->addViolation(); + } + } + } + /** * Validation callback that checks if the addresses are valid (do not have - * two addresses with the same validFrom date) + * two addresses with the same validFrom date). * * This method add violation errors. */ @@ -1090,65 +826,363 @@ class Person implements HasCenterInterface $context ->buildViolation('Two addresses has the same validFrom date') ->atPath('addresses') - ->addViolation() - ; + ->addViolation(); } } - - const ERROR_PERIODS_ARE_COLLAPSING = 1; // when two different periods - // have days in commun - const ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD = 2; // where there exist - // a period opened and another one after it - /** - * Function used for validation that check if the accompanying periods of - * the person are not collapsing (i.e. have not shared days) or having - * a period after an open period. - * - * @return true | array True if the accompanying periods are not collapsing, - * an array with data for displaying the error + * Check if the person is opened. */ - public function checkAccompanyingPeriodsAreNotCollapsing() + public function isOpen(): bool { - $periods = $this->getAccompanyingPeriodsOrdered(); - $periodsNbr = sizeof($periods); - $i = 0; - - while($i < $periodsNbr - 1) { - $periodI = $periods[$i]; - $periodAfterI = $periods[$i + 1]; - - if($periodI->isOpen()) { - return array( - 'result' => self::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD, - 'dateOpening' => $periodAfterI->getOpeningDate(), - 'dateClosing' => $periodAfterI->getClosingDate(), - 'date' => $periodI->getOpeningDate() - ); - } elseif ($periodI->getClosingDate() >= $periodAfterI->getOpeningDate()) { - return array( - 'result' => self::ERROR_PERIODS_ARE_COLLAPSING, - 'dateOpening' => $periodI->getOpeningDate(), - - 'dateClosing' => $periodI->getClosingDate(), - 'date' => $periodAfterI->getOpeningDate() - ); + foreach ($this->getAccompanyingPeriods() as $period) { + if ($period->isOpen()) { + return true; } - $i++; } - return true; + return false; } - - public function getFullnameCanonical() : string + + /** + * set the Person file as open at the given date. + * + * For updating a opening's date, you should update AccompanyingPeriod instance + * directly. + * + * For closing a file, @see this::close + * + * To check if the Person and its accompanying period is consistent, use validation. + */ + public function open(AccompanyingPeriod $accompanyingPeriod): void { - return $this->fullnameCanonical; + $this->proxyAccompanyingPeriodOpenState = true; + $this->addAccompanyingPeriod($accompanyingPeriod); } - - public function setFullnameCanonical($fullnameCanonical) : Person + + /** + * Remove AccompanyingPeriod. + */ + public function removeAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): void { - $this->fullnameCanonical = $fullnameCanonical; + $participation = $this->participationsContainAccompanyingPeriod($accompanyingPeriod); + + if (!null === $participation) { + $participation->setEndDate(DateTimeImmutable::class); + $this->accompanyingPeriodParticipations->removeElement($participation); + } + } + + public function removeAddress(Address $address) + { + $this->addresses->removeElement($address); + } + + /** + * @return $this + */ + public function removeAltName(PersonAltName $altName) + { + if ($this->altNames->contains($altName)) { + $altName->setPerson(null); + $this->altNames->removeElement($altName); + } + return $this; } + + /** + * @return $this + */ + public function removeOtherPhoneNumber(PersonPhone $otherPhoneNumber) + { + if ($this->otherPhoneNumbers->contains($otherPhoneNumber)) { + $this->otherPhoneNumbers->removeElement($otherPhoneNumber); + } + + return $this; + } + + /** + * @return $this + */ + public function setAltNames(Collection $altNames) + { + $this->altNames = $altNames; + + return $this; + } + + /** + * Set birthdate. + * + * @param DateTime $birthdate + * + * @return Person + */ + public function setBirthdate($birthdate) + { + $this->birthdate = $birthdate; + + return $this; + } + + /** + * Set the center. + * + * @return \Chill\PersonBundle\Entity\Person + */ + public function setCenter(Center $center) + { + $this->center = $center; + + return $this; + } + + /** + * Set cFData. + * + * @param array $cFData + * + * @return Report + */ + public function setCFData($cFData) + { + $this->cFData = $cFData; + + return $this; + } + + /** + * Set contactInfo. + * + * @param string $contactInfo + * + * @return Person + */ + public function setcontactInfo($contactInfo) + { + if (null === $contactInfo) { + $contactInfo = ''; + } + + $this->contactInfo = $contactInfo; + + return $this; + } + + /** + * Set countryOfBirth. + * + * @param Chill\MainBundle\Entity\Country $countryOfBirth + * + * @return Person + */ + public function setCountryOfBirth(?Country $countryOfBirth = null) + { + $this->countryOfBirth = $countryOfBirth; + + return $this; + } + + /** + * Set email. + * + * @param string $email + * + * @return Person + */ + public function setEmail($email) + { + if (null === $email) { + $email = ''; + } + + $this->email = $email; + + return $this; + } + + /** + * Set firstName. + * + * @param string $firstName + * + * @return Person + */ + public function setFirstName($firstName) + { + $this->firstName = $firstName; + + return $this; + } + + public function setFullnameCanonical($fullnameCanonical): Person + { + $this->fullnameCanonical = $fullnameCanonical; + + return $this; + } + + /** + * Set gender. + * + * @param string $gender + * + * @return Person + */ + public function setGender($gender) + { + $this->gender = $gender; + + return $this; + } + + /** + * Set lastName. + * + * @param string $lastName + * + * @return Person + */ + public function setLastName($lastName) + { + $this->lastName = $lastName; + + return $this; + } + + /** + * Set maritalStatus. + * + * @param MaritalStatus $maritalStatus + * + * @return Person + */ + public function setMaritalStatus(?MaritalStatus $maritalStatus = null) + { + $this->maritalStatus = $maritalStatus; + + return $this; + } + + /** + * Set memo. + * + * @param string $memo + * + * @return Person + */ + public function setMemo($memo) + { + if (null === $memo) { + $memo = ''; + } + + if ($this->memo !== $memo) { + $this->memo = $memo; + } + + return $this; + } + + /** + * Set mobilenumber. + * + * @param string $mobilenumber + * + * @return Person + */ + public function setMobilenumber($mobilenumber = '') + { + $this->mobilenumber = $mobilenumber; + + return $this; + } + + /** + * Set nationality. + * + * @param Chill\MainBundle\Entity\Country $nationality + * + * @return Person + */ + public function setNationality(?Country $nationality = null) + { + $this->nationality = $nationality; + + return $this; + } + + /** + * @return $this + */ + public function setOtherPhoneNumbers(Collection $otherPhoneNumbers) + { + $this->otherPhoneNumbers = $otherPhoneNumbers; + + return $this; + } + + /** + * Set phonenumber. + * + * @param string $phonenumber + * + * @return Person + */ + public function setPhonenumber($phonenumber = '') + { + $this->phonenumber = $phonenumber; + + return $this; + } + + /** + * Set placeOfBirth. + * + * @param string $placeOfBirth + * + * @return Person + */ + public function setPlaceOfBirth($placeOfBirth) + { + if (null === $placeOfBirth) { + $placeOfBirth = ''; + } + + $this->placeOfBirth = $placeOfBirth; + + return $this; + } + + /** + * Set spokenLanguages. + * + * @param type $spokenLanguages + * + * @return Person + */ + public function setSpokenLanguages($spokenLanguages) + { + $this->spokenLanguages = $spokenLanguages; + + return $this; + } + + /** + * This private function scan accompanyingPeriodParticipations Collection, + * searching for a given AccompanyingPeriod. + */ + private function participationsContainAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod): ?AccompanyingPeriodParticipation + { + foreach ($this->accompanyingPeriodParticipations as $participation) { + /** @var AccompanyingPeriodParticipation $participation */ + if ($participation->getAccompanyingPeriod() === $accompanyingPeriod) { + return $participation; + } + } + + return null; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php b/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php index c5295487e..03a30c865 100644 --- a/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php +++ b/src/Bundle/ChillPersonBundle/Entity/PersonAltName.php @@ -1,11 +1,18 @@ id; } + /** + * Get key. + * + * @return string + */ + public function getKey() + { + return $this->key; + } + + /** + * Get label. + * + * @return string + */ + public function getLabel() + { + return $this->label; + } + + public function getPerson(): Person + { + return $this->person; + } + /** * Set key. * @@ -70,16 +101,6 @@ class PersonAltName return $this; } - /** - * Get key. - * - * @return string - */ - public function getKey() - { - return $this->key; - } - /** * Set label. * @@ -95,31 +116,12 @@ class PersonAltName } /** - * Get label. - * - * @return string - */ - public function getLabel() - { - return $this->label; - } - - /** - * @return Person - */ - public function getPerson(): Person - { - return $this->person; - } - - /** - * @param Person|null $person * @return $this */ public function setPerson(?Person $person = null) { $this->person = $person; - + return $this; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/PersonNotDuplicate.php b/src/Bundle/ChillPersonBundle/Entity/PersonNotDuplicate.php index ce2a1c26f..f85c5e0fc 100644 --- a/src/Bundle/ChillPersonBundle/Entity/PersonNotDuplicate.php +++ b/src/Bundle/ChillPersonBundle/Entity/PersonNotDuplicate.php @@ -1,12 +1,20 @@ date = new \DateTime(); - } - - public function getId() - { - return $this->id; - } - - public function setId($id) - { - $this->id = $id; - } - - public function getPerson1() - { - return $this->person1; - } - - public function setPerson1(Person $person1) - { - $this->person1 = $person1; - } - - public function getPerson2() - { - return $this->person2; - } - - public function setPerson2(Person $person2) - { - $this->person2 = $person2; + $this->date = new DateTime(); } public function getDate() @@ -90,9 +69,19 @@ class PersonNotDuplicate return $this->date; } - public function setDate(\DateTime $date) + public function getId() { - $this->date = $date; + return $this->id; + } + + public function getPerson1() + { + return $this->person1; + } + + public function getPerson2() + { + return $this->person2; } public function getUser() @@ -100,6 +89,26 @@ class PersonNotDuplicate return $this->user; } + public function setDate(DateTime $date) + { + $this->date = $date; + } + + public function setId($id) + { + $this->id = $id; + } + + public function setPerson1(Person $person1) + { + $this->person1 = $person1; + } + + public function setPerson2(Person $person2) + { + $this->person2 = $person2; + } + public function setUser(User $user) { $this->user = $user; diff --git a/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php b/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php index 4a2ffaf28..b309bf2f6 100644 --- a/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php +++ b/src/Bundle/ChillPersonBundle/Entity/PersonPhone.php @@ -1,18 +1,35 @@ date = new \DateTime(); + $this->date = new DateTime(); + } + + public function getDate(): DateTime + { + return $this->date; + } + + public function getDescription(): ?string + { + return $this->description; } public function getId(): int @@ -63,9 +80,9 @@ class PersonPhone return $this->person; } - public function setPerson(Person $person): void + public function getPhonenumber(): string { - $this->person = $person; + return $this->phonenumber; } public function getType(): string @@ -73,24 +90,14 @@ class PersonPhone return $this->type; } - public function setType(string $type): void + public function isEmpty(): bool { - $this->type = $type; + return empty($this->getDescription()) && empty($this->getPhonenumber()); } - public function getPhonenumber(): string + public function setDate(DateTime $date): void { - return $this->phonenumber; - } - - public function setPhonenumber(string $phonenumber): void - { - $this->phonenumber = $phonenumber; - } - - public function getDescription(): ?string - { - return $this->description; + $this->date = $date; } public function setDescription(?string $description): void @@ -98,18 +105,18 @@ class PersonPhone $this->description = $description; } - public function getDate(): \DateTime + public function setPerson(Person $person): void { - return $this->date; + $this->person = $person; } - public function setDate(\DateTime $date): void + public function setPhonenumber(string $phonenumber): void { - $this->date = $date; + $this->phonenumber = $phonenumber; } - - public function isEmpty(): bool + + public function setType(string $type): void { - return empty($this->getDescription()) && empty($this->getPhonenumber()); + $this->type = $type; } } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php index 9e6dcbaa6..a1cad6261 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Evaluation.php @@ -1,8 +1,16 @@ delay; + } + public function getId(): ?int { return $this->id; } + public function getNotificationDelay(): ?DateInterval + { + return $this->notificationDelay; + } + + public function getSocialAction(): ?SocialAction + { + return $this->socialAction; + } + public function getTitle(): array { return $this->title; } - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; - } - - public function getDelay(): ?\DateInterval - { - return $this->delay; - } - - public function setDelay(\DateInterval $delay): self + public function setDelay(DateInterval $delay): self { $this->delay = $delay; return $this; } - public function getNotificationDelay(): ?\DateInterval - { - return $this->notificationDelay; - } - - public function setNotificationDelay(\DateInterval $notificationDelay): self + public function setNotificationDelay(DateInterval $notificationDelay): self { $this->notificationDelay = $notificationDelay; return $this; } - public function getSocialAction(): ?SocialAction - { - return $this->socialAction; - } - public function setSocialAction(?SocialAction $socialAction): self { $this->socialAction = $socialAction; return $this; } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php index c92e9a736..11510bdfc 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Goal.php @@ -1,8 +1,16 @@ results = new ArrayCollection(); } - public function getTitle(): array - { - return $this->title; - } - - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; - } - - public function getDesactivationDate(): ?\DateTimeInterface - { - return $this->desactivationDate; - } - - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self - { - $this->desactivationDate = $desactivationDate; - - return $this; - } - - /** - * @return Collection|SocialAction[] - */ - public function getSocialActions(): Collection - { - return $this->socialActions; - } - - public function addSocialAction(SocialAction $socialAction): self - { - if (!$this->socialActions->contains($socialAction)) { - $this->socialActions[] = $socialAction; - } - - return $this; - } - - public function removeSocialAction(SocialAction $socialAction): self - { - $this->socialActions->removeElement($socialAction); - - return $this; - } - - /** - * @return Collection|Result[] - */ - public function getResults(): Collection - { - return $this->results; - } - public function addResult(Result $result): self { if (!$this->results->contains($result)) { @@ -112,10 +64,66 @@ class Goal return $this; } + public function addSocialAction(SocialAction $socialAction): self + { + if (!$this->socialActions->contains($socialAction)) { + $this->socialActions[] = $socialAction; + } + + return $this; + } + + public function getDesactivationDate(): ?DateTimeInterface + { + return $this->desactivationDate; + } + + /** + * @return Collection|Result[] + */ + public function getResults(): Collection + { + return $this->results; + } + + /** + * @return Collection|SocialAction[] + */ + public function getSocialActions(): Collection + { + return $this->socialActions; + } + + public function getTitle(): array + { + return $this->title; + } + public function removeResult(Result $result): self { $this->results->removeElement($result); return $this; } + + public function removeSocialAction(SocialAction $socialAction): self + { + $this->socialActions->removeElement($socialAction); + + return $this; + } + + public function setDesactivationDate(?DateTimeInterface $desactivationDate): self + { + $this->desactivationDate = $desactivationDate; + + return $this; + } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php index be38b1757..ab49d4bc5 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/Result.php @@ -1,10 +1,18 @@ accompanyingPeriodWorkGoals = new ArrayCollection(); } - public function getId(): ?int - { - return $this->id; - } - - public function getTitle(): array - { - return $this->title; - } - - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; - } - - public function getDesactivationDate(): ?\DateTimeInterface - { - return $this->desactivationDate; - } - - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self - { - $this->desactivationDate = $desactivationDate; - - return $this; - } - - /** - * @return Collection|SocialAction[] - */ - public function getSocialActions(): Collection - { - return $this->socialActions; - } - - public function addSocialAction(SocialAction $socialAction): self - { - if (!$this->socialActions->contains($socialAction)) { - $this->socialActions[] = $socialAction; - } - - return $this; - } - - public function removeSocialAction(SocialAction $socialAction): self - { - $this->socialActions->removeElement($socialAction); - - return $this; - } - - /** - * @return Collection|Goal[] - */ - public function getGoals(): Collection - { - return $this->goals; - } - - public function addGoal(Goal $goal): self - { - if (!$this->goals->contains($goal)) { - $this->goals[] = $goal; - } - - return $this; - } - - public function removeGoal(Goal $goal): self - { - $this->goals->removeElement($goal); - - return $this; - } - - /** - * @return Collection|AccompanyingPeriodWork[] - */ - public function getAccompanyingPeriodWorks(): Collection - { - return $this->accompanyingPeriodWorks; - } - public function addAccompanyingPeriodWork(AccompanyingPeriodWork $accompanyingPeriod): self { if (!$this->accompanyingPeriodWorks->contains($accompanyingPeriod)) { @@ -154,26 +77,83 @@ class Result return $this; } - public function removeAccompanyingPeriodWork(AccompanyingPeriodWork $accompanyingPeriod): self + public function addAccompanyingPeriodWorkGoal(AccompanyingPeriodWorkGoal $accompanyingPeriodWorkGoal): self { - $this->accompanyingPeriodWorks->removeElement($accompanyingPeriod); + if (!$this->accompanyingPeriodWorkGoals->contains($accompanyingPeriodWorkGoal)) { + $this->accompanyingPeriodWorkGoals[] = $accompanyingPeriodWorkGoal; + } + + return $this; + } + + public function addGoal(Goal $goal): self + { + if (!$this->goals->contains($goal)) { + $this->goals[] = $goal; + } + + return $this; + } + + public function addSocialAction(SocialAction $socialAction): self + { + if (!$this->socialActions->contains($socialAction)) { + $this->socialActions[] = $socialAction; + } return $this; } /** - * @return Collection|AccompanyingPeriodWorkGoal[] + * @return AccompanyingPeriodWorkGoal[]|Collection */ public function getAccompanyingPeriodWorkGoals(): Collection { return $this->accompanyingPeriodWorkGoals; } - public function addAccompanyingPeriodWorkGoal(AccompanyingPeriodWorkGoal $accompanyingPeriodWorkGoal): self + /** + * @return AccompanyingPeriodWork[]|Collection + */ + public function getAccompanyingPeriodWorks(): Collection { - if (!$this->accompanyingPeriodWorkGoals->contains($accompanyingPeriodWorkGoal)) { - $this->accompanyingPeriodWorkGoals[] = $accompanyingPeriodWorkGoal; - } + return $this->accompanyingPeriodWorks; + } + + public function getDesactivationDate(): ?DateTimeInterface + { + return $this->desactivationDate; + } + + /** + * @return Collection|Goal[] + */ + public function getGoals(): Collection + { + return $this->goals; + } + + public function getId(): ?int + { + return $this->id; + } + + /** + * @return Collection|SocialAction[] + */ + public function getSocialActions(): Collection + { + return $this->socialActions; + } + + public function getTitle(): array + { + return $this->title; + } + + public function removeAccompanyingPeriodWork(AccompanyingPeriodWork $accompanyingPeriod): self + { + $this->accompanyingPeriodWorks->removeElement($accompanyingPeriod); return $this; } @@ -184,4 +164,32 @@ class Result return $this; } + + public function removeGoal(Goal $goal): self + { + $this->goals->removeElement($goal); + + return $this; + } + + public function removeSocialAction(SocialAction $socialAction): self + { + $this->socialActions->removeElement($socialAction); + + return $this; + } + + public function setDesactivationDate(?DateTimeInterface $desactivationDate): self + { + $this->desactivationDate = $desactivationDate; + + return $this; + } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php index 64413d987..d65d2ec7f 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialAction.php @@ -1,8 +1,17 @@ children = new ArrayCollection(); @@ -69,43 +78,30 @@ class SocialAction $this->results = new ArrayCollection(); } - public function getId(): ?int + public function addChild(self $child): self { - return $this->id; - } - - public function getDesactivationDate(): ?\DateTimeInterface - { - return $this->desactivationDate; - } - - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self - { - $this->desactivationDate = $desactivationDate; + if (!$this->children->contains($child)) { + $this->children[] = $child; + $child->setParent($this); + } return $this; } - public function getIssue(): ?SocialIssue + public function addGoal(Goal $goal): self { - return $this->issue; - } - - public function setIssue(?SocialIssue $issue): self - { - $this->issue = $issue; + if (!$this->goals->contains($goal)) { + $this->goals[] = $goal; + } return $this; } - public function getParent(): ?self + public function addResult(Result $result): self { - return $this->parent; - } - - public function setParent(?self $parent): self - { - $this->parent = $parent; + if (!$this->results->contains($result)) { + $this->results[] = $result; + } return $this; } @@ -118,14 +114,50 @@ class SocialAction return $this->children; } - public function addChild(self $child): self + public function getDefaultNotificationDelay(): ?DateInterval { - if (!$this->children->contains($child)) { - $this->children[] = $child; - $child->setParent($this); - } + return $this->defaultNotificationDelay; + } - return $this; + public function getDesactivationDate(): ?DateTimeInterface + { + return $this->desactivationDate; + } + + /** + * @return Collection|Goal[] + */ + public function getGoals(): Collection + { + return $this->goals; + } + + public function getId(): ?int + { + return $this->id; + } + + public function getIssue(): ?SocialIssue + { + return $this->issue; + } + + public function getParent(): ?self + { + return $this->parent; + } + + /** + * @return Collection|Result[] + */ + public function getResults(): Collection + { + return $this->results; + } + + public function getTitle(): array + { + return $this->title; } public function removeChild(self $child): self @@ -140,47 +172,6 @@ class SocialAction return $this; } - public function getDefaultNotificationDelay(): ?\DateInterval - { - return $this->defaultNotificationDelay; - } - - public function setDefaultNotificationDelay(\DateInterval $defaultNotificationDelay): self - { - $this->defaultNotificationDelay = $defaultNotificationDelay; - - return $this; - } - - public function getTitle(): array - { - return $this->title; - } - - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; - } - - /** - * @return Collection|Goal[] - */ - public function getGoals(): Collection - { - return $this->goals; - } - - public function addGoal(Goal $goal): self - { - if (!$this->goals->contains($goal)) { - $this->goals[] = $goal; - } - - return $this; - } - public function removeGoal(Goal $goal): self { $this->goals->removeElement($goal); @@ -188,27 +179,45 @@ class SocialAction return $this; } - /** - * @return Collection|Result[] - */ - public function getResults(): Collection - { - return $this->results; - } - - public function addResult(Result $result): self - { - if (!$this->results->contains($result)) { - $this->results[] = $result; - } - - return $this; - } - public function removeResult(Result $result): self { $this->results->removeElement($result); return $this; } + + public function setDefaultNotificationDelay(DateInterval $defaultNotificationDelay): self + { + $this->defaultNotificationDelay = $defaultNotificationDelay; + + return $this; + } + + public function setDesactivationDate(?DateTimeInterface $desactivationDate): self + { + $this->desactivationDate = $desactivationDate; + + return $this; + } + + public function setIssue(?SocialIssue $issue): self + { + $this->issue = $issue; + + return $this; + } + + public function setParent(?self $parent): self + { + $this->parent = $parent; + + return $this; + } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php index cfec01751..eadf52fd7 100644 --- a/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php +++ b/src/Bundle/ChillPersonBundle/Entity/SocialWork/SocialIssue.php @@ -1,8 +1,16 @@ children = new ArrayCollection(); $this->socialActions = new ArrayCollection(); } - public function getId(): ?int - { - return $this->id; - } - - public function getParent(): ?self - { - return $this->parent; - } - - public function setParent(?self $parent): self - { - $this->parent = $parent; - - return $this; - } - - /** - * @return Collection|self[] - */ - public function getChildren(): Collection - { - return $this->children; - } - public function addChild(self $child): self { if (!$this->children->contains($child)) { @@ -86,40 +69,37 @@ class SocialIssue return $this; } - public function removeChild(self $child): self + public function addSocialAction(SocialAction $socialAction): self { - if ($this->children->removeElement($child)) { - // set the owning side to null (unless already changed) - if ($child->getParent() === $this) { - $child->setParent(null); - } + if (!$this->socialActions->contains($socialAction)) { + $this->socialActions[] = $socialAction; + $socialAction->setSocialIssue($this); } return $this; } - public function getDesactivationDate(): ?\DateTimeInterface + /** + * @return Collection|self[] + */ + public function getChildren(): Collection + { + return $this->children; + } + + public function getDesactivationDate(): ?DateTimeInterface { return $this->desactivationDate; } - public function setDesactivationDate(?\DateTimeInterface $desactivationDate): self + public function getId(): ?int { - $this->desactivationDate = $desactivationDate; - - return $this; + return $this->id; } - public function getTitle(): array + public function getParent(): ?self { - return $this->title; - } - - public function setTitle(array $title): self - { - $this->title = $title; - - return $this; + return $this->parent; } /** @@ -130,11 +110,18 @@ class SocialIssue return $this->socialActions; } - public function addSocialAction(SocialAction $socialAction): self + public function getTitle(): array { - if (!$this->socialActions->contains($socialAction)) { - $this->socialActions[] = $socialAction; - $socialAction->setSocialIssue($this); + return $this->title; + } + + public function removeChild(self $child): self + { + if ($this->children->removeElement($child)) { + // set the owning side to null (unless already changed) + if ($child->getParent() === $this) { + $child->setParent(null); + } } return $this; @@ -151,4 +138,25 @@ class SocialIssue return $this; } + + public function setDesactivationDate(?DateTimeInterface $desactivationDate): self + { + $this->desactivationDate = $desactivationDate; + + return $this; + } + + public function setParent(?self $parent): self + { + $this->parent = $parent; + + return $this; + } + + public function setTitle(array $title): self + { + $this->title = $title; + + return $this; + } } diff --git a/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php b/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php index c21d5733a..bd235ec2f 100644 --- a/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php +++ b/src/Bundle/ChillPersonBundle/Export/AbstractAccompanyingPeriodExportElement.php @@ -1,59 +1,45 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Export; use Doctrine\ORM\QueryBuilder; +use LogicException; + +use function in_array; -/** - * - * - */ class AbstractAccompanyingPeriodExportElement { + /** + * Add the accompanying period alias to the query. + * + * @throws LogicException if the "person" alias is not present and attaching accompanying period is not possible + */ + protected function addJoinAccompanyingPeriod(QueryBuilder $query): void + { + if (false === $this->havingAccompanyingPeriodInJoin($query)) { + if (false === in_array('person', $query->getAllAliases())) { + throw new LogicException("the alias 'person' does not exists in " + . 'query builder'); + } + + $query->join('person.accompanyingPeriods', 'accompanying_period'); + } + } + /** * Return true if "accompanying_period" alias is present in the query alises. - * - * @param QueryBuilder $query - * @return bool */ protected function havingAccompanyingPeriodInJoin(QueryBuilder $query): bool { $joins = $query->getDQLPart('join') ?? []; - - return (\in_array('accompanying_period', $query->getAllAliases())); - } - - /** - * Add the accompanying period alias to the query - * - * @param QueryBuilder $query - * @return void - * @throws \LogicException if the "person" alias is not present and attaching accompanying period is not possible - */ - protected function addJoinAccompanyingPeriod(QueryBuilder $query): void - { - if (FALSE === $this->havingAccompanyingPeriodInJoin($query)) { - if (FALSE === \in_array('person', $query->getAllAliases())) { - throw new \LogicException("the alias 'person' does not exists in " - . "query builder"); - } - - $query->join('person.accompanyingPeriods', 'accompanying_period'); - } + + return in_array('accompanying_period', $query->getAllAliases()); } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php index 7b2e6c1b4..e375d60e2 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/AgeAggregator.php @@ -1,51 +1,35 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; +use Chill\MainBundle\Export\ExportElementValidatedInterface; +use DateTime; use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\DateType; -use Chill\MainBundle\Export\ExportElementValidatedInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ -class AgeAggregator implements AggregatorInterface, +class AgeAggregator implements + AggregatorInterface, ExportElementValidatedInterface { /** - * - * @var + * @var */ protected $translator; - + public function __construct($translator) { $this->translator = $translator; } - public function addRole() { return null; @@ -65,48 +49,47 @@ class AgeAggregator implements AggregatorInterface, public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_age_calculation', DateType::class, array( - 'label' => "Calculate age in relation to this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', - 'format' => 'dd-MM-yyyy' - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['date_age_calculation'] === null) { - $context->buildViolation("The date should not be empty") - ->addViolation(); - } + $builder->add('date_age_calculation', DateType::class, [ + 'label' => 'Calculate age in relation to this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', + 'format' => 'dd-MM-yyyy', + ]); } public function getLabels($key, array $values, $data) { - return function($value) { - if ($value === '_header') { - return "Age"; + return function ($value) { + if ('_header' === $value) { + return 'Age'; } - - if ($value === NULL) { - return $this->translator->trans("without data"); + + if (null === $value) { + return $this->translator->trans('without data'); } - + return $value; }; } public function getQueryKeys($data) { - return array( - 'person_age' - ); + return [ + 'person_age', + ]; } public function getTitle() { - return "Aggregate by age"; + return 'Aggregate by age'; } + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['date_age_calculation']) { + $context->buildViolation('The date should not be empty') + ->addViolation(); + } + } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php index 5bb08af60..acbe34b59 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/CountryOfBirthAggregator.php @@ -1,106 +1,66 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Util\CountriesInfo; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Util\CountriesInfo; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Context\ExecutionContextInterface; - -/** - * - * - * @author Julien Fastré - */ -class CountryOfBirthAggregator implements AggregatorInterface, +class CountryOfBirthAggregator implements + AggregatorInterface, ExportElementValidatedInterface { /** - * * @var EntityRepository */ protected $countriesRepository; /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; /** - * * @var TranslatorInterface */ protected $translator; - public function __construct(EntityRepository $countriesRepository, - TranslatableStringHelper $translatableStringHelper, - TranslatorInterface $translator) - { + public function __construct( + EntityRepository $countriesRepository, + TranslatableStringHelper $translatableStringHelper, + TranslatorInterface $translator + ) { $this->countriesRepository = $countriesRepository; $this->translatableStringHelper = $translatableStringHelper; $this->translator = $translator; } - public function applyOn() + public function addRole() { - return 'person'; - } - - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('group_by_level', ChoiceType::class, array( - 'choices' => array( - 'Group by continents' => 'continent', - 'Group by country' => 'country' - ), - 'expanded' => true, - 'multiple' => false - )); - - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['group_by_level'] === null) { - $context->buildViolation("You should select an option") - ->addViolation(); - } + return null; } public function alterQuery(QueryBuilder $qb, $data) { // add a clause in select part - if ($data['group_by_level'] === 'country') { + if ('country' === $data['group_by_level']) { $qb->addSelect('countryOfBirth.countryCode as country_of_birth_aggregator'); - } elseif ($data['group_by_level'] === 'continent') { + } elseif ('continent' === $data['group_by_level']) { $clause = 'CASE ' . 'WHEN countryOfBirth.countryCode IN(:cob_africa_codes) THEN \'AF\' ' . 'WHEN countryOfBirth.countryCode IN(:cob_asia_codes) THEN \'AS\' ' @@ -113,24 +73,24 @@ class CountryOfBirthAggregator implements AggregatorInterface, . 'END as country_of_birth_aggregator '; $qb->addSelect($clause); $params = - array( + [ 'cob_africa_codes' => CountriesInfo::getCountriesCodeByContinent('AF'), 'cob_asia_codes' => CountriesInfo::getCountriesCodeByContinent('AS'), 'cob_europe_codes' => CountriesInfo::getCountriesCodeByContinent('EU'), 'cob_north_america_codes' => CountriesInfo::getCountriesCodeByContinent('NA'), 'cob_south_america_codes' => CountriesInfo::getCountriesCodeByContinent('SA'), 'cob_oceania_codes' => CountriesInfo::getCountriesCodeByContinent('OC'), - 'cob_antartica_codes' => CountriesInfo::getCountriesCodeByContinent('AN') - ); + 'cob_antartica_codes' => CountriesInfo::getCountriesCodeByContinent('AN'), + ]; + foreach ($params as $k => $v) { $qb->setParameter($k, $v); } } else { - throw new \LogicException("The group_by_level '".$data['group_by_level'] - ." is not known."); + throw new LogicException("The group_by_level '" . $data['group_by_level'] + . ' is not known.'); } - $qb->leftJoin('person.countryOfBirth', 'countryOfBirth'); // add group by @@ -141,46 +101,45 @@ class CountryOfBirthAggregator implements AggregatorInterface, } else { $qb->groupBy('country_of_birth_aggregator'); } - } - public function getTitle() + public function applyOn() { - return "Group people by country of birth"; + return 'person'; } - public function getQueryKeys($data) + public function buildForm(FormBuilderInterface $builder) { - return array('country_of_birth_aggregator'); - } - - public function addRole() - { - return NULL; + $builder->add('group_by_level', ChoiceType::class, [ + 'choices' => [ + 'Group by continents' => 'continent', + 'Group by country' => 'country', + ], + 'expanded' => true, + 'multiple' => false, + ]); } public function getLabels($key, array $values, $data) { - if ($data['group_by_level'] === 'country') { + if ('country' === $data['group_by_level']) { $qb = $this->countriesRepository->createQueryBuilder('c'); $countries = $qb - ->andWhere($qb->expr()->in('c.countryCode', ':countries')) - ->setParameter('countries', $values) - ->getQuery() - ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); + ->andWhere($qb->expr()->in('c.countryCode', ':countries')) + ->setParameter('countries', $values) + ->getQuery() + ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); // initialize array and add blank key for null values $labels[''] = $this->translator->trans('without data'); $labels['_header'] = $this->translator->trans('Country of birth'); - foreach($countries as $row) { + + foreach ($countries as $row) { $labels[$row['c_countryCode']] = $this->translatableStringHelper->localize($row['c_name']); } - - - } elseif ($data['group_by_level'] === 'continent') { - - $labels = array( + } elseif ('continent' === $data['group_by_level']) { + $labels = [ 'EU' => $this->translator->trans('Europe'), 'AS' => $this->translator->trans('Asia'), 'AN' => $this->translator->trans('Antartica'), @@ -188,15 +147,31 @@ class CountryOfBirthAggregator implements AggregatorInterface, 'SA' => $this->translator->trans('South America'), 'NA' => $this->translator->trans('North America'), 'OC' => $this->translator->trans('Oceania'), - '' => $this->translator->trans('without data'), - '_header' => $this->translator->trans('Continent of birth') - ); + '' => $this->translator->trans('without data'), + '_header' => $this->translator->trans('Continent of birth'), + ]; } - - return function($value) use ($labels) { + return function ($value) use ($labels) { return $labels[$value]; }; + } + public function getQueryKeys($data) + { + return ['country_of_birth_aggregator']; + } + + public function getTitle() + { + return 'Group people by country of birth'; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['group_by_level']) { + $context->buildViolation('You should select an option') + ->addViolation(); + } } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php index 6f4314a76..a1aa28b6e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/GenderAggregator.php @@ -1,103 +1,87 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Translation\TranslatorInterface; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Export\Declarations; +use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class GenderAggregator implements AggregatorInterface { - /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct(TranslatorInterface $translator) { $this->translator = $translator; } - + + public function addRole() + { + return null; + } + + public function alterQuery(QueryBuilder $qb, $data) + { + $qb->addSelect('person.gender as gender'); + + $qb->addGroupBy('gender'); + } + public function applyOn() { return Declarations::PERSON_TYPE; } - - + public function buildForm(FormBuilderInterface $builder) { - } - - public function alterQuery(QueryBuilder $qb, $data) - { - $qb->addSelect('person.gender as gender'); - - $qb->addGroupBy('gender'); - - } - - public function getTitle() - { - return "Group people by gender"; - } - - public function getQueryKeys($data) - { - return array('gender'); - } - public function getLabels($key, array $values, $data) - { - return function($value) { + { + return function ($value) { switch ($value) { - case Person::FEMALE_GENDER : + case Person::FEMALE_GENDER: return $this->translator->trans('woman'); - case Person::MALE_GENDER : + + case Person::MALE_GENDER: return $this->translator->trans('man'); + case Person::BOTH_GENDER: return $this->translator->trans('both'); + case null: return $this->translator->trans('Not given'); - case '_header' : + + case '_header': return $this->translator->trans('Gender'); + default: - throw new \LogicException(sprintf("The value %s is not valid", $value)); + throw new LogicException(sprintf('The value %s is not valid', $value)); } }; } - public function addRole() + public function getQueryKeys($data) { - return NULL; + return ['gender']; } + public function getTitle() + { + return 'Group people by gender'; + } } diff --git a/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php b/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php index d708957f7..c542ebbb1 100644 --- a/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php +++ b/src/Bundle/ChillPersonBundle/Export/Aggregator/NationalityAggregator.php @@ -1,105 +1,66 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Aggregator; use Chill\MainBundle\Export\AggregatorInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\EntityRepository; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Util\CountriesInfo; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\MainBundle\Util\CountriesInfo; +use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; +use LogicException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - * @author Julien Fastré - */ -class NationalityAggregator implements AggregatorInterface, +class NationalityAggregator implements + AggregatorInterface, ExportElementValidatedInterface { /** - * * @var EntityRepository */ protected $countriesRepository; /** - * * @var TranslatableStringHelper */ protected $translatableStringHelper; /** - * * @var TranslatorInterface */ protected $translator; - public function __construct(EntityRepository $countriesRepository, - TranslatableStringHelper $translatableStringHelper, - TranslatorInterface $translator) - { + public function __construct( + EntityRepository $countriesRepository, + TranslatableStringHelper $translatableStringHelper, + TranslatorInterface $translator + ) { $this->countriesRepository = $countriesRepository; $this->translatableStringHelper = $translatableStringHelper; $this->translator = $translator; } - public function applyOn() + public function addRole() { - return 'person'; - } - - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('group_by_level', ChoiceType::class, array( - 'choices' => array( - 'Group by continents' => 'continent', - 'Group by country' => 'country' - ), - 'expanded' => true, - 'multiple' => false - )); - - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['group_by_level'] === null) { - $context->buildViolation("You should select an option") - ->addViolation(); - } + return null; } public function alterQuery(QueryBuilder $qb, $data) { // add a clause in select part - if ($data['group_by_level'] === 'country') { + if ('country' === $data['group_by_level']) { $qb->addSelect('nationality.countryCode as nationality_aggregator'); - } elseif ($data['group_by_level'] === 'continent') { + } elseif ('continent' === $data['group_by_level']) { $clause = 'CASE ' . 'WHEN nationality.countryCode IN(:africa_codes) THEN \'AF\' ' . 'WHEN nationality.countryCode IN(:asia_codes) THEN \'AS\' ' @@ -112,24 +73,24 @@ class NationalityAggregator implements AggregatorInterface, . 'END as nationality_aggregator '; $qb->addSelect($clause); $params = - array( + [ 'africa_codes' => CountriesInfo::getCountriesCodeByContinent('AF'), 'asia_codes' => CountriesInfo::getCountriesCodeByContinent('AS'), 'europe_codes' => CountriesInfo::getCountriesCodeByContinent('EU'), 'north_america_codes' => CountriesInfo::getCountriesCodeByContinent('NA'), 'south_america_codes' => CountriesInfo::getCountriesCodeByContinent('SA'), 'oceania_codes' => CountriesInfo::getCountriesCodeByContinent('OC'), - 'antartica_codes' => CountriesInfo::getCountriesCodeByContinent('AN') - ); + 'antartica_codes' => CountriesInfo::getCountriesCodeByContinent('AN'), + ]; + foreach ($params as $k => $v) { $qb->setParameter($k, $v); } } else { - throw new \LogicException("The group_by_level '".$data['group_by_level'] - ." is not known."); + throw new LogicException("The group_by_level '" . $data['group_by_level'] + . ' is not known.'); } - $qb->leftJoin('person.nationality', 'nationality'); // add group by @@ -140,46 +101,45 @@ class NationalityAggregator implements AggregatorInterface, } else { $qb->groupBy('nationality_aggregator'); } - } - public function getTitle() + public function applyOn() { - return "Group people by nationality"; + return 'person'; } - public function getQueryKeys($data) + public function buildForm(FormBuilderInterface $builder) { - return array('nationality_aggregator'); - } - - public function addRole() - { - return NULL; + $builder->add('group_by_level', ChoiceType::class, [ + 'choices' => [ + 'Group by continents' => 'continent', + 'Group by country' => 'country', + ], + 'expanded' => true, + 'multiple' => false, + ]); } public function getLabels($key, array $values, $data) { - if ($data['group_by_level'] === 'country') { + if ('country' === $data['group_by_level']) { $qb = $this->countriesRepository->createQueryBuilder('c'); $countries = $qb - ->andWhere($qb->expr()->in('c.countryCode', ':countries')) - ->setParameter('countries', $values) - ->getQuery() - ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); + ->andWhere($qb->expr()->in('c.countryCode', ':countries')) + ->setParameter('countries', $values) + ->getQuery() + ->getResult(\Doctrine\ORM\Query::HYDRATE_SCALAR); // initialize array and add blank key for null values $labels[''] = $this->translator->trans('without data'); $labels['_header'] = $this->translator->trans('Nationality'); - foreach($countries as $row) { + + foreach ($countries as $row) { $labels[$row['c_countryCode']] = $this->translatableStringHelper->localize($row['c_name']); } - - - } elseif ($data['group_by_level'] === 'continent') { - - $labels = array( + } elseif ('continent' === $data['group_by_level']) { + $labels = [ 'EU' => $this->translator->trans('Europe'), 'AS' => $this->translator->trans('Asia'), 'AN' => $this->translator->trans('Antartica'), @@ -187,15 +147,31 @@ class NationalityAggregator implements AggregatorInterface, 'SA' => $this->translator->trans('South America'), 'NA' => $this->translator->trans('North America'), 'OC' => $this->translator->trans('Oceania'), - '' => $this->translator->trans('without data'), - '_header' => $this->translator->trans('Continent') - ); + '' => $this->translator->trans('without data'), + '_header' => $this->translator->trans('Continent'), + ]; } - - return function($value) use ($labels) { + return function ($value) use ($labels) { return $labels[$value]; }; + } + public function getQueryKeys($data) + { + return ['nationality_aggregator']; + } + + public function getTitle() + { + return 'Group people by nationality'; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + if (null === $data['group_by_level']) { + $context->buildViolation('You should select an option') + ->addViolation(); + } } } diff --git a/src/Bundle/ChillPersonBundle/Export/Declarations.php b/src/Bundle/ChillPersonBundle/Export/Declarations.php index bbdf3e8e4..8d2b9e951 100644 --- a/src/Bundle/ChillPersonBundle/Export/Declarations.php +++ b/src/Bundle/ChillPersonBundle/Export/Declarations.php @@ -1,32 +1,20 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export; /** * This class declare constants used for the export framework. - * - * - * @author Julien Fastré */ abstract class Declarations { - CONST PERSON_TYPE = 'person'; - CONST PERSON_IMPLIED_IN = 'person_implied_in'; + public const PERSON_IMPLIED_IN = 'person_implied_in'; + + public const PERSON_TYPE = 'person'; } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php index 0431095ec..426b5bb95 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/CountPerson.php @@ -1,136 +1,115 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Export; use Chill\MainBundle\Export\ExportInterface; -use Doctrine\ORM\QueryBuilder; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\Query; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Export\Declarations; use Chill\MainBundle\Export\FormatterInterface; +use Chill\PersonBundle\Export\Declarations; +use Chill\PersonBundle\Security\Authorization\PersonVoter; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use LogicException; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class CountPerson implements ExportInterface { /** - * * @var EntityManagerInterface */ protected $entityManager; - + public function __construct( - EntityManagerInterface $em - ) - { + EntityManagerInterface $em + ) { $this->entityManager = $em; } - - /** - * - */ - public function getType() + + public function buildForm(FormBuilderInterface $builder) { - return Declarations::PERSON_TYPE; } - + + public function getAllowedFormattersTypes() + { + return [FormatterInterface::TYPE_TABULAR]; + } + public function getDescription() { - return "Count peoples by various parameters."; + return 'Count peoples by various parameters.'; } - - public function getTitle() + + public function getLabels($key, array $values, $data) { - return "Count peoples"; + if ('export_result' !== $key) { + throw new LogicException("the key {$key} is not used by this export"); + } + + $labels = array_combine($values, $values); + $labels['_header'] = $this->getTitle(); + + return function ($value) use ($labels) { + return $labels[$value]; + }; } - - public function requiredRole() + + public function getQueryKeys($data) { - return new Role(PersonVoter::STATS); + return ['export_result']; } - - /** - * Initiate the query - * - * @param QueryBuilder $qb - * @return QueryBuilder - */ - public function initiateQuery(array $requiredModifiers, array $acl, array $data = array()) - { - $centers = array_map(function($el) { return $el['center']; }, $acl); - - $qb = $this->entityManager->createQueryBuilder(); - - $qb->select('COUNT(person.id) AS export_result') - ->from('ChillPersonBundle:Person', 'person') - ->join('person.center', 'center') - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - ; - - - return $qb; - } - + public function getResult($qb, $data) { return $qb->getQuery()->getResult(Query::HYDRATE_SCALAR); } - - public function getQueryKeys($data) - { - return array('export_result'); - } - - public function getLabels($key, array $values, $data) - { - if ($key !== 'export_result') { - throw new \LogicException("the key $key is not used by this export"); - } - - $labels = array_combine($values, $values); - $labels['_header'] = $this->getTitle(); - - return function($value) use ($labels) { - return $labels[$value]; - }; - } - - public function getAllowedFormattersTypes() - { - return array(FormatterInterface::TYPE_TABULAR); - } - - public function buildForm(FormBuilderInterface $builder) { + public function getTitle() + { + return 'Count peoples'; } - + + public function getType() + { + return Declarations::PERSON_TYPE; + } + + /** + * Initiate the query. + * + * @return QueryBuilder + */ + public function initiateQuery(array $requiredModifiers, array $acl, array $data = []) + { + $centers = array_map(function ($el) { + return $el['center']; + }, $acl); + + $qb = $this->entityManager->createQueryBuilder(); + + $qb->select('COUNT(person.id) AS export_result') + ->from('ChillPersonBundle:Person', 'person') + ->join('person.center', 'center') + ->andWhere('center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); + + return $qb; + } + + public function requiredRole() + { + return new Role(PersonVoter::STATS); + } + public function supportsModifiers() { - return array(Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN); + return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN]; } - } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php index dc36c8c57..d2b9824e3 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPerson.php @@ -1,75 +1,84 @@ entityManager = $em; $this->translator = $translator; @@ -77,123 +86,73 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface $this->customFieldProvider = $customFieldProvider; } - /** - * {@inheritDoc} - * - * @param FormBuilderInterface $builder - */ public function buildForm(FormBuilderInterface $builder) { $choices = array_combine($this->fields, $this->fields); foreach ($this->getCustomFields() as $cf) { - $choices - [$this->translatableStringHelper->localize($cf->getName())] + $choices[$this->translatableStringHelper->localize($cf->getName())] = $cf->getSlug(); } // Add a checkbox to select fields - $builder->add('fields', ChoiceType::class, array( + $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, 'choices' => $choices, - 'label' => 'Fields to include in export', - 'choice_attr' => function($val, $key, $index) { + 'label' => 'Fields to include in export', + 'choice_attr' => function ($val, $key, $index) { // add a 'data-display-target' for address fields if (substr($val, 0, 8) === 'address_') { return ['data-display-target' => 'address_date']; - } else { - return []; } + + return []; }, - 'constraints' => [new Callback(array( - 'callback' => function($selected, ExecutionContextInterface $context) { + 'constraints' => [new Callback([ + 'callback' => function ($selected, ExecutionContextInterface $context) { if (count($selected) === 0) { $context->buildViolation('You must select at least one element') ->atPath('fields') ->addViolation(); } - } - ))] - )); + }, + ])], + ]); // add a date field for addresses - $builder->add('address_date', DateType::class, array( - 'label' => "Address valid at this date", - 'data' => new \DateTime(), - 'attr' => array( 'class' => 'datepicker'), - 'widget'=> 'single_text', + $builder->add('address_date', DateType::class, [ + 'label' => 'Address valid at this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'required' => false, - 'block_name' => 'list_export_form_address_date' - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - // get the field starting with address_ - $addressFields = array_filter(function($el) { - return substr($el, 0, 8) === 'address_'; - }, $this->fields); - - // check if there is one field starting with address in data - if (count(array_intersect($data['fields'], $addressFields)) > 0) { - // if a field address is checked, the date must not be empty - if (empty($data['address_date'])) { - $context - ->buildViolation("You must set this date if an address is checked") - ->atPath('address_date') - ->addViolation(); - } - } + 'block_name' => 'list_export_form_address_date', + ]); } /** - * Get custom fields associated with person - * - * @return CustomField[] - */ - private function getCustomFields() - { - return $this->entityManager - ->createQuery("SELECT cf " - . "FROM ChillCustomFieldsBundle:CustomField cf " - . "JOIN cf.customFieldGroup g " - . "WHERE cf.type != :title AND g.entity LIKE :entity") - ->setParameters(array( - 'title' => 'title', - 'entity' => \addcslashes(Person::class, "\\") - )) - ->getResult(); - } - - /** - * {@inheritDoc} - * * @return type */ public function getAllowedFormattersTypes() { - return array(FormatterInterface::TYPE_LIST); + return [FormatterInterface::TYPE_LIST]; } /** - * {@inheritDoc} - * * @return string */ public function getDescription() { - return "Create a list of people according to various filters."; + return 'Create a list of people according to various filters.'; } /** - * {@inheritDoc} - * * @param type $key - * @param array $values * @param type $data + * * @return type */ public function getLabels($key, array $values, $data) @@ -202,224 +161,148 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface case 'birthdate': // for birthdate, we have to transform the string into a date // to format the date correctly. - return function($value) { - if ($value === '_header') { return 'birthdate'; } - - if (empty($value)) - { - return ""; + return function ($value) { + if ('_header' === $value) { + return 'birthdate'; } - $date = \DateTime::createFromFormat('Y-m-d', $value); + if (empty($value)) { + return ''; + } + + $date = DateTime::createFromFormat('Y-m-d', $value); // check that the creation could occurs. - if ($date === false) { - throw new \Exception(sprintf("The value %s could " - . "not be converted to %s", $value, \DateTime::class)); + if (false === $date) { + throw new Exception(sprintf('The value %s could ' + . 'not be converted to %s', $value, DateTime::class)); } return $date->format('d-m-Y'); }; - case 'gender' : + + case 'gender': // for gender, we have to translate men/women statement - return function($value) { - if ($value === '_header') { return 'gender'; } + return function ($value) { + if ('_header' === $value) { + return 'gender'; + } return $this->translator->trans($value); }; + case 'countryOfBirth': case 'nationality': $countryRepository = $this->entityManager ->getRepository('ChillMainBundle:Country'); // load all countries in a single query - $countryRepository->findBy(array('countryCode' => $values)); + $countryRepository->findBy(['countryCode' => $values]); - return function($value) use ($key, $countryRepository) { - if ($value === '_header') { return \strtolower($key); } + return function ($value) use ($key, $countryRepository) { + if ('_header' === $value) { + return strtolower($key); + } - if ($value === NULL) { + if (null === $value) { return $this->translator->trans('no data'); } $country = $countryRepository->find($value); return $this->translatableStringHelper->localize( - $country->getName()); + $country->getName() + ); }; - case 'address_country_name': - return function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } - if ($value === NULL) { + case 'address_country_name': + return function ($value) use ($key) { + if ('_header' === $value) { + return strtolower($key); + } + + if (null === $value) { return ''; } return $this->translatableStringHelper->localize(json_decode($value, true)); }; + case 'address_isnoaddress': - return function($value) use ($key) { - if ($value === '_header') { return 'address.address_homeless'; } - + return function ($value) { + if ('_header' === $value) { + return 'address.address_homeless'; + } + if ($value) { return 'X'; - } else { - return ''; } + + return ''; }; + default: // for fields which are associated with person if (in_array($key, $this->fields)) { - return function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } + return function ($value) use ($key) { + if ('_header' === $value) { + return strtolower($key); + } return $value; - - }; + }; } else { return $this->getLabelForCustomField($key, $values, $data); } } - - } - - private function getLabelForCustomField($key, array $values, $data) - { - // for fields which are custom fields - /* @var $cf CustomField */ - $cf = $this->entityManager - ->getRepository(CustomField::class) - ->findOneBy(array('slug' => $this->DQLToSlug($key))); - $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); - $defaultFunction = function($value) use ($cf) { - if ($value === '_header') { - return $this->translatableStringHelper->localize($cf->getName()); - } - - return $this->customFieldProvider - ->getCustomFieldByType($cf->getType()) - ->render(json_decode($value, true), $cf, 'csv'); - }; - - if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { - return function($value) use ($cf, $cfType, $key) { - $slugChoice = $this->extractInfosFromSlug($key)['additionnalInfos']['choiceSlug']; - $decoded = \json_decode($value, true); - - if ($value === '_header') { - - $label = $cfType->getChoices($cf)[$slugChoice]; - - return $this->translatableStringHelper->localize($cf->getName()) - .' | '.$label; - } - - if ($slugChoice === '_other' and $cfType->isChecked($cf, $choiceSlug, $decoded)) { - return $cfType->extractOtherValue($cf, $decoded); - } else { - return $cfType->isChecked($cf, $slugChoice, $decoded); - } - }; - - } else { - return $defaultFunction; - } } /** - * {@inheritDoc} - * * @param type $data + * * @return type */ public function getQueryKeys($data) { - $fields = array(); + $fields = []; foreach ($data['fields'] as $key) { if (in_array($key, $this->fields)) { $fields[] = $key; } } - + // add the key from slugs and return - return \array_merge($fields, \array_keys($this->slugs)); + return array_merge($fields, array_keys($this->slugs)); } - /** - * clean a slug to be usable by DQL - * - * @param string $slugsanitize - * @param string $type the type of the customfield, if required (currently only for choices) - * @return string - */ - private function slugToDQL($slug, $type = "default", array $additionalInfos = []) - { - $uid = 'slug_'.\uniqid(); - - $this->slugs[$uid] = [ - 'slug' => $slug, - 'type' => $type, - 'additionnalInfos' => $additionalInfos - ]; - - return $uid; - } - - private function DQLToSlug($cleanedSlug) - { - return $this->slugs[$cleanedSlug]['slug']; - } - - /** - * - * @param type $cleanedSlug - * @return an array with keys = 'slug', 'type', 'additionnalInfo' - */ - private function extractInfosFromSlug($slug) - { - return $this->slugs[$slug]; - } - - /** - * {@inheritDoc} - * - */ public function getResult($query, $data) { return $query->getQuery()->getResult(Query::HYDRATE_SCALAR); } /** - * {@inheritDoc} - * * @return string */ public function getTitle() { - return "List peoples"; + return 'List peoples'; } - /** - * {@inheritDoc} - * - */ public function getType() { return Declarations::PERSON_TYPE; } - /** - * {@inheritDoc} - * - */ - 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 - if (!\array_key_exists('fields', $data)) { - throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " - . "have been checked"); + if (!array_key_exists('fields', $data)) { + throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields ' + . 'have been checked'); } $qb = $this->entityManager->createQueryBuilder(); @@ -430,7 +313,9 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface case 'countryOfBirth': case 'nationality': $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f)); + break; + case 'address_street_address_1': case 'address_street_address_2': case 'address_valid_from': @@ -439,14 +324,16 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface case 'address_country_name': case 'address_country_code': case 'address_isnoaddress': - $qb->addSelect(sprintf( 'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s', // get the part after address_ strtoupper(substr($f, 8)), - $f)); + $f + )); $qb->setParameter('address_date', $data['address_date']); + break; + default: $qb->addSelect(sprintf('person.%s as %s', $f, $f)); } @@ -455,49 +342,163 @@ class ListPerson implements ListInterface, ExportElementValidatedInterface foreach ($this->getCustomFields() as $cf) { $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); + if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { - foreach($cfType->getChoices($cf) as $choiceSlug => $label) { - $slug = $this->slugToDQL($cf->getSlug(), 'choice', [ 'choiceSlug' => $choiceSlug ]); + foreach ($cfType->getChoices($cf) as $choiceSlug => $label) { + $slug = $this->slugToDQL($cf->getSlug(), 'choice', ['choiceSlug' => $choiceSlug]); $qb->addSelect( - sprintf('GET_JSON_FIELD_BY_KEY(person.cFData, :slug%s) AS %s', - $slug, $slug)); + sprintf( + 'GET_JSON_FIELD_BY_KEY(person.cFData, :slug%s) AS %s', + $slug, + $slug + ) + ); $qb->setParameter(sprintf('slug%s', $slug), $cf->getSlug()); } } else { $slug = $this->slugToDQL($cf->getSlug()); $qb->addSelect( - sprintf('GET_JSON_FIELD_BY_KEY(person.cFData, :slug%s) AS %s', - $slug, $slug)); + sprintf( + 'GET_JSON_FIELD_BY_KEY(person.cFData, :slug%s) AS %s', + $slug, + $slug + ) + ); $qb->setParameter(sprintf('slug%s', $slug), $cf->getSlug()); } } $qb - ->from('ChillPersonBundle:Person', 'person') - ->join('person.center', 'center') - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - ; - + ->from('ChillPersonBundle:Person', 'person') + ->join('person.center', 'center') + ->andWhere('center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); return $qb; } - /** - * - * {@inheritDoc} - */ public function requiredRole() { return new Role(PersonVoter::LISTS); } - /** - * - * {@inheritDoc} - */ public function supportsModifiers() { - return array(Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN); + return [Declarations::PERSON_TYPE, Declarations::PERSON_IMPLIED_IN]; + } + + public function validateForm($data, ExecutionContextInterface $context) + { + // get the field starting with address_ + $addressFields = array_filter(function ($el) { + return substr($el, 0, 8) === 'address_'; + }, $this->fields); + + // check if there is one field starting with address in data + if (count(array_intersect($data['fields'], $addressFields)) > 0) { + // if a field address is checked, the date must not be empty + if (empty($data['address_date'])) { + $context + ->buildViolation('You must set this date if an address is checked') + ->atPath('address_date') + ->addViolation(); + } + } + } + + private function DQLToSlug($cleanedSlug) + { + return $this->slugs[$cleanedSlug]['slug']; + } + + /** + * @param mixed $slug + * + * @return an array with keys = 'slug', 'type', 'additionnalInfo' + */ + private function extractInfosFromSlug($slug) + { + return $this->slugs[$slug]; + } + + /** + * Get custom fields associated with person. + * + * @return CustomField[] + */ + private function getCustomFields() + { + return $this->entityManager + ->createQuery('SELECT cf ' + . 'FROM ChillCustomFieldsBundle:CustomField cf ' + . 'JOIN cf.customFieldGroup g ' + . 'WHERE cf.type != :title AND g.entity LIKE :entity') + ->setParameters([ + 'title' => 'title', + 'entity' => addcslashes(Person::class, '\\'), + ]) + ->getResult(); + } + + private function getLabelForCustomField($key, array $values, $data) + { + // for fields which are custom fields + /* @var $cf CustomField */ + $cf = $this->entityManager + ->getRepository(CustomField::class) + ->findOneBy(['slug' => $this->DQLToSlug($key)]); + $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); + $defaultFunction = function ($value) use ($cf) { + if ('_header' === $value) { + return $this->translatableStringHelper->localize($cf->getName()); + } + + return $this->customFieldProvider + ->getCustomFieldByType($cf->getType()) + ->render(json_decode($value, true), $cf, 'csv'); + }; + + if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { + return function ($value) use ($cf, $cfType, $key) { + $slugChoice = $this->extractInfosFromSlug($key)['additionnalInfos']['choiceSlug']; + $decoded = \json_decode($value, true); + + if ('_header' === $value) { + $label = $cfType->getChoices($cf)[$slugChoice]; + + return $this->translatableStringHelper->localize($cf->getName()) + . ' | ' . $label; + } + + if ('_other' === $slugChoice and $cfType->isChecked($cf, $choiceSlug, $decoded)) { + return $cfType->extractOtherValue($cf, $decoded); + } + + return $cfType->isChecked($cf, $slugChoice, $decoded); + }; + } else { + return $defaultFunction; + } + } + + /** + * clean a slug to be usable by DQL. + * + * @param string $type the type of the customfield, if required (currently only for choices) + * @param mixed $slug + * + * @return string + */ + private function slugToDQL($slug, $type = 'default', array $additionalInfos = []) + { + $uid = 'slug_' . uniqid(); + + $this->slugs[$uid] = [ + 'slug' => $slug, + 'type' => $type, + 'additionnalInfos' => $additionalInfos, + ]; + + return $uid; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php index 366e952ba..f1852da88 100644 --- a/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php +++ b/src/Bundle/ChillPersonBundle/Export/Export/ListPersonDuplicate.php @@ -1,11 +1,16 @@ entityManager = $em; $this->translator = $translator; $this->router = $router; - $this->baseUrl = $routeParameters['scheme']. - '://'.$routeParameters['host']; + $this->baseUrl = $routeParameters['scheme'] . + '://' . $routeParameters['host']; } - /** - * {@inheritDoc} - * - * @return string - */ - public function getTitle() - { - return "List duplicates"; - } - - /** - * {@inheritDoc} - * - * @return string - */ - public function getDescription() - { - return "Create a list of duplicate people."; - } - - /** - * {@inheritDoc} - * - * @param FormBuilderInterface $builder - */ public function buildForm(FormBuilderInterface $builder) { $builder->add('precision', NumberType::class, [ @@ -97,27 +76,23 @@ class ListPersonDuplicate implements DirectExportInterface, ExportElementValidat ]); } - public function validateForm($data, ExecutionContextInterface $context) - { - - } - public function generate(array $acl, array $data = []): Response { $values = []; $values[] = $this->getHeaders(); $result = $this->getResult($data); + foreach ($result as $row) { $values[] = [ $row['id1'], $row['firstname1'], $row['lastname1'], - $this->baseUrl.$this->router->generate('chill_person_view', ['person_id' => $row['id1']]), + $this->baseUrl . $this->router->generate('chill_person_view', ['person_id' => $row['id1']]), $row['id2'], $row['firstname2'], $row['lastname2'], - $this->baseUrl.$this->router->generate('chill_person_view', ['person_id' => $row['id2']]), + $this->baseUrl . $this->router->generate('chill_person_view', ['person_id' => $row['id2']]), ]; } @@ -125,15 +100,15 @@ class ListPersonDuplicate implements DirectExportInterface, ExportElementValidat $spreadsheet->getActiveSheet()->fromArray($values); // Make links clickable - for ($i = 1; $i <= $spreadsheet->getActiveSheet()->getHighestDataRow(); $i++) { - $spreadsheet->getActiveSheet()->getCell('D'.$i)->getHyperlink() - ->setUrl($spreadsheet->getActiveSheet()->getCell('D'.$i)->getValue()); - $spreadsheet->getActiveSheet()->getCell('H'.$i)->getHyperlink() - ->setUrl($spreadsheet->getActiveSheet()->getCell('H'.$i)->getValue()); + for ($i = 1; $spreadsheet->getActiveSheet()->getHighestDataRow() >= $i; ++$i) { + $spreadsheet->getActiveSheet()->getCell('D' . $i)->getHyperlink() + ->setUrl($spreadsheet->getActiveSheet()->getCell('D' . $i)->getValue()); + $spreadsheet->getActiveSheet()->getCell('H' . $i)->getHyperlink() + ->setUrl($spreadsheet->getActiveSheet()->getCell('H' . $i)->getValue()); } $writer = new Xlsx($spreadsheet); - $temp_file = sys_get_temp_dir().'/'.uniqid('export_').'.xlsx'; + $temp_file = sys_get_temp_dir() . '/' . uniqid('export_') . '.xlsx'; $writer->save($temp_file); $response = new BinaryFileResponse($temp_file); @@ -143,6 +118,45 @@ class ListPersonDuplicate implements DirectExportInterface, ExportElementValidat return $response; } + /** + * @return string + */ + public function getDescription() + { + return 'Create a list of duplicate people.'; + } + + /** + * @return string + */ + public function getTitle() + { + return 'List duplicates'; + } + + public function requiredRole(): Role + { + return new Role(PersonVoter::DUPLICATE); + } + + public function validateForm($data, ExecutionContextInterface $context) + { + } + + protected function getHeaders(): array + { + return [ + $this->translator->trans('Departure folder number'), + $this->translator->trans('Last name'), + $this->translator->trans('First name'), + $this->translator->trans('Link'), + $this->translator->trans('Arrival folder number'), + $this->translator->trans('Last name'), + $this->translator->trans('First name'), + $this->translator->trans('Link'), + ]; + } + protected function getResult($data = []) { $precision = $data['precision'] ?? self::PRECISION_DEFAULT_VALUE; @@ -180,23 +194,4 @@ class ListPersonDuplicate implements DirectExportInterface, ExportElementValidat return $statement->fetchAll(); } - - protected function getHeaders(): array - { - return [ - $this->translator->trans('Departure folder number'), - $this->translator->trans('Last name'), - $this->translator->trans('First name'), - $this->translator->trans('Link'), - $this->translator->trans('Arrival folder number'), - $this->translator->trans('Last name'), - $this->translator->trans('First name'), - $this->translator->trans('Link'), - ]; - } - - public function requiredRole(): Role - { - return new Role(PersonVoter::DUPLICATE); - } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php index 7179de4d3..25d05f747 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodClosingFilter.php @@ -1,33 +1,22 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -38,10 +27,11 @@ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportEl public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX( $qb->expr()->lte('accompanying_period.closingDate', ':date_to'), - $qb->expr()->gte('accompanying_period.closingDate', ':date_from')); + $qb->expr()->gte('accompanying_period.closingDate', ':date_from') + ); $qb->andWhere($clause); $qb->setParameter('date_from', $data['date_from'], Type::DATE); @@ -55,31 +45,31 @@ class AccompanyingPeriodClosingFilter extends AbstractAccompanyingPeriodExportEl public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, array( - 'label' => "Having an accompanying period closed after this date", - 'data' => new \DateTime("-1 month"), - )); - - $builder->add('date_to', ChillDateType::class, array( - 'label' => "Having an accompanying period closed before this date", - 'data' => new \DateTime(), - )); + $builder->add('date_from', ChillDateType::class, [ + 'label' => 'Having an accompanying period closed after this date', + 'data' => new DateTime('-1 month'), + ]); + + $builder->add('date_to', ChillDateType::class, [ + 'label' => 'Having an accompanying period closed before this date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string') { return [ - "Filtered by accompanying period: persons having an accompanying period" - . " closed between the %date_from% and %date_to%", + 'Filtered by accompanying period: persons having an accompanying period' + . ' closed between the %date_from% and %date_to%', [ '%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(): string { - return "Filter by accompanying period: closed between two dates"; + return 'Filter by accompanying period: closed between two dates'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php index 40f7dd501..08dbc0974 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodFilter.php @@ -1,33 +1,22 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -38,18 +27,18 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX(); - + $clause->add( $qb->expr()->lte('accompanying_period.openingDate', ':date_to') - ); + ); $clause->add( $qb->expr()->orX( $qb->expr()->gte('accompanying_period.closingDate', ':date_from'), $qb->expr()->isNull('accompanying_period.closingDate') - ) - ); + ) + ); $qb->andWhere($clause); $qb->setParameter('date_from', $data['date_from'], Type::DATE); @@ -63,33 +52,33 @@ class AccompanyingPeriodFilter extends AbstractAccompanyingPeriodExportElement i public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, array( - 'label' => "Having an accompanying period opened after this date", - 'data' => new \DateTime("-1 month"), - )); - - $builder->add('date_to', ChillDateType::class, array( - 'label' => "Having an accompanying period ending before this date, or " - . "still opened at this date", - 'data' => new \DateTime(), - )); + $builder->add('date_from', ChillDateType::class, [ + 'label' => 'Having an accompanying period opened after this date', + 'data' => new DateTime('-1 month'), + ]); + + $builder->add('date_to', ChillDateType::class, [ + 'label' => 'Having an accompanying period ending before this date, or ' + . 'still opened at this date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string') { return [ - "Filtered by accompanying period: persons having an accompanying period" - . " opened after the %date_from% and closed before the %date_to% (or still opened " - . "at the %date_to%)", + 'Filtered by accompanying period: persons having an accompanying period' + . ' opened after the %date_from% and closed before the %date_to% (or still opened ' + . 'at the %date_to%)', [ '%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(): string { - return "Filter by accompanying period: active period"; + return 'Filter by accompanying period: active period'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php index 26a8818df..bd9cbd082 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/AccompanyingPeriodOpeningFilter.php @@ -1,33 +1,22 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Export\Filter; use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Form\Type\ChillDateType; -use Doctrine\DBAL\Types\Type; use Chill\PersonBundle\Export\AbstractAccompanyingPeriodExportElement; +use DateTime; +use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; -/** - * - * - */ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportElement implements FilterInterface { public function addRole() @@ -38,10 +27,11 @@ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportEl public function alterQuery(QueryBuilder $qb, $data) { $this->addJoinAccompanyingPeriod($qb); - + $clause = $qb->expr()->andX( $qb->expr()->lte('accompanying_period.openingDate', ':date_to'), - $qb->expr()->gte('accompanying_period.openingDate', ':date_from')); + $qb->expr()->gte('accompanying_period.openingDate', ':date_from') + ); $qb->andWhere($clause); $qb->setParameter('date_from', $data['date_from'], Type::DATE); @@ -55,31 +45,31 @@ class AccompanyingPeriodOpeningFilter extends AbstractAccompanyingPeriodExportEl public function buildForm(FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, array( - 'label' => "Having an accompanying period opened after this date", - 'data' => new \DateTime("-1 month"), - )); - - $builder->add('date_to', ChillDateType::class, array( - 'label' => "Having an accompanying period opened before this date", - 'data' => new \DateTime(), - )); + $builder->add('date_from', ChillDateType::class, [ + 'label' => 'Having an accompanying period opened after this date', + 'data' => new DateTime('-1 month'), + ]); + + $builder->add('date_to', ChillDateType::class, [ + 'label' => 'Having an accompanying period opened before this date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string') { return [ - "Filtered by accompanying period: persons having an accompanying period" - . " opened between the %date_from% and %date_to%", + 'Filtered by accompanying period: persons having an accompanying period' + . ' opened between the %date_from% and %date_to%', [ '%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(): string { - return "Filter by accompanying period: starting between two dates"; + return 'Filter by accompanying period: starting between two dates'; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/BirthdateFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/BirthdateFilter.php index 234d6bd3e..518df3d4b 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/BirthdateFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/BirthdateFilter.php @@ -1,43 +1,23 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Filter; +use Chill\MainBundle\Export\ExportElementValidatedInterface; use Chill\MainBundle\Export\FilterInterface; +use DateTime; +use Doctrine\ORM\Query\Expr; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Validator\Context\ExecutionContextInterface; -use Symfony\Component\Validator\Constraints; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Doctrine\ORM\Query\Expr; -use Chill\MainBundle\Form\Type\Export\FilterType; -use Symfony\Component\Form\FormError; -use Chill\MainBundle\Export\ExportElementValidatedInterface; -/** - * - * - * @author Julien Fastré - */ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterface { - public function addRole() { return null; @@ -46,15 +26,18 @@ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterfac public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->between('person.birthdate', ':date_from', - ':date_to'); + $clause = $qb->expr()->between( + 'person.birthdate', + ':date_from', + ':date_to' + ); if ($where instanceof Expr\Andx) { $where->add($clause); } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('date_from', $data['date_from']); $qb->setParameter('date_to', $data['date_to']); @@ -67,59 +50,30 @@ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterfac public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', DateType::class, array( - 'label' => "Born after this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + $builder->add('date_from', DateType::class, [ + 'label' => 'Born after this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - $builder->add('date_to', DateType::class, array( - 'label' => "Born before this date", - 'data' => new \DateTime(), - 'attr' => array('class' => 'datepicker'), - 'widget'=> 'single_text', + ]); + + $builder->add('date_to', DateType::class, [ + 'label' => 'Born before this date', + 'data' => new DateTime(), + 'attr' => ['class' => 'datepicker'], + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', - )); - - } - - public function validateForm($data, ExecutionContextInterface $context) - { - $date_from = $data['date_from']; - $date_to = $data['date_to']; - - if ($date_from === null) { - $context->buildViolation('The "date from" should not be empty') - //->atPath('date_from') - ->addViolation(); - } - - if ($date_to === null) { - $context->buildViolation('The "date to" should not be empty') - //->atPath('date_to') - ->addViolation(); - } - - if ( - ($date_from !== null && $date_to !== null) - && - $date_from >= $date_to - ) { - $context->buildViolation('The date "date to" should be after the ' - . 'date given in "date from" field') - ->addViolation(); - } + ]); } public function describeAction($data, $format = 'string') { - return array('Filtered by person\'s birtdate: ' - . 'between %date_from% and %date_to%', array( + return ['Filtered by person\'s birtdate: ' + . 'between %date_from% and %date_to%', [ '%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() @@ -127,4 +81,30 @@ class BirthdateFilter implements FilterInterface, ExportElementValidatedInterfac return 'Filter by person\'s birthdate'; } + public function validateForm($data, ExecutionContextInterface $context) + { + $date_from = $data['date_from']; + $date_to = $data['date_to']; + + if (null === $date_from) { + $context->buildViolation('The "date from" should not be empty') + //->atPath('date_from') + ->addViolation(); + } + + if (null === $date_to) { + $context->buildViolation('The "date to" should not be empty') + //->atPath('date_to') + ->addViolation(); + } + + if ( + (null !== $date_from && null !== $date_to) + && $date_from >= $date_to + ) { + $context->buildViolation('The date "date to" should be after the ' + . 'date given in "date from" field') + ->addViolation(); + } + } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php index 7db76f6a7..d3028b28e 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/GenderFilter.php @@ -1,90 +1,53 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Filter; -use Chill\MainBundle\Export\FilterInterface; -use Symfony\Component\Form\FormBuilderInterface; -use Chill\PersonBundle\Entity\Person; -use Doctrine\ORM\QueryBuilder; -use Doctrine\ORM\Query\Expr; -use Symfony\Component\Security\Core\Role\Role; use Chill\MainBundle\Export\ExportElementValidatedInterface; -use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Chill\MainBundle\Export\FilterInterface; +use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\QueryBuilder; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - * @author Julien Fastré - */ -class GenderFilter implements FilterInterface, +use function array_filter; +use function implode; +use function in_array; + +class GenderFilter implements + FilterInterface, ExportElementValidatedInterface { /** - * * @var TranslatorInterface */ protected $translator; - - function __construct(TranslatorInterface $translator) + + public function __construct(TranslatorInterface $translator) { $this->translator = $translator; } - public function applyOn() + public function addRole() { - return 'person'; - } - - /** - * - */ - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('accepted_genders', ChoiceType::class, array( - 'choices' => array( - 'Woman' => Person::FEMALE_GENDER, - 'Man' => Person::MALE_GENDER, - 'Both' => Person::BOTH_GENDER, - 'Not given' => 'null' - ), - 'multiple' => true, - 'expanded' => true - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if (!is_array($data['accepted_genders']) || count($data['accepted_genders']) === 0 ) { - $context->buildViolation("You should select an option") - ->addViolation(); - } + return null; } public function alterQuery(QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); $isIn = $qb->expr()->in('person.gender', ':person_gender'); - - if (!\in_array('null', $data['accepted_genders'])) { + + if (!in_array('null', $data['accepted_genders'])) { $clause = $isIn; } else { $clause = $qb->expr()->orX($isIn, $qb->expr()->isNull('person.gender')); @@ -97,15 +60,53 @@ class GenderFilter implements FilterInterface, } $qb->add('where', $where); - $qb->setParameter('person_gender', \array_filter( + $qb->setParameter('person_gender', array_filter( $data['accepted_genders'], - function($el) { - return $el !== 'null'; - })); + function ($el) { + return 'null' !== $el; + } + )); + } + + public function applyOn() + { + return 'person'; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('accepted_genders', ChoiceType::class, [ + 'choices' => [ + 'Woman' => Person::FEMALE_GENDER, + 'Man' => Person::MALE_GENDER, + 'Both' => Person::BOTH_GENDER, + 'Not given' => 'null', + ], + 'multiple' => true, + 'expanded' => true, + ]); + } + + public function describeAction($data, $format = 'string') + { + $genders = []; + + foreach ($data['accepted_genders'] as $g) { + if ('null' === $g) { + $genders[] = $this->translator->trans('Not given'); + } else { + $genders[] = $this->translator->trans($g); + } + } + + return [ + 'Filtering by genders: only %genders%', + ['%genders%' => implode(', ', $genders)], + ]; } /** - * A title which will be used in the label for the form + * A title which will be used in the label for the form. * * @return string */ @@ -114,26 +115,11 @@ class GenderFilter implements FilterInterface, return 'Filter by person gender'; } - public function addRole() + public function validateForm($data, ExecutionContextInterface $context) { - return NULL; - } - - public function describeAction($data, $format = 'string') - { - $genders = []; - - foreach ($data['accepted_genders'] as $g) { - if ('null' === $g) { - $genders[] = $this->translator->trans('Not given'); - } else { - $genders[] = $this->translator->trans($g); - } + if (!is_array($data['accepted_genders']) || count($data['accepted_genders']) === 0) { + $context->buildViolation('You should select an option') + ->addViolation(); } - - return [ - "Filtering by genders: only %genders%", - [ "%genders%" => \implode(", ", $genders)] - ]; } } diff --git a/src/Bundle/ChillPersonBundle/Export/Filter/NationalityFilter.php b/src/Bundle/ChillPersonBundle/Export/Filter/NationalityFilter.php index d6dc52af8..449af1913 100644 --- a/src/Bundle/ChillPersonBundle/Export/Filter/NationalityFilter.php +++ b/src/Bundle/ChillPersonBundle/Export/Filter/NationalityFilter.php @@ -1,45 +1,29 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Export\Filter; -use Symfony\Component\Form\FormBuilderInterface; -use Doctrine\ORM\QueryBuilder; -use Chill\MainBundle\Export\FilterInterface; -use Doctrine\ORM\Query\Expr; -use Chill\MainBundle\Templating\TranslatableStringHelper; -use Doctrine\ORM\EntityRepository; use Chill\MainBundle\Entity\Country; use Chill\MainBundle\Export\ExportElementValidatedInterface; +use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Form\Type\Select2CountryType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Doctrine\ORM\Query\Expr; +use Doctrine\ORM\QueryBuilder; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Validator\Context\ExecutionContextInterface; -/** - * - * - * @author Julien Fastré - */ -class NationalityFilter implements FilterInterface, +class NationalityFilter implements + FilterInterface, ExportElementValidatedInterface { /** - * * @var TranslatableStringHelper */ private $translatableStringHelper; @@ -49,25 +33,9 @@ class NationalityFilter implements FilterInterface, $this->translatableStringHelper = $helper; } - public function applyOn() + public function addRole() { - return 'person'; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder->add('nationalities', Select2CountryType::class, array( - 'placeholder' => 'Choose countries' - )); - - } - - public function validateForm($data, ExecutionContextInterface $context) - { - if ($data['nationalities'] === null) { - $context->buildViolation("A nationality must be selected") - ->addViolation(); - } + return null; } public function alterQuery(QueryBuilder $qb, $data) @@ -82,7 +50,33 @@ class NationalityFilter implements FilterInterface, } $qb->add('where', $where); - $qb->setParameter('person_nationality', array($data['nationalities'])); + $qb->setParameter('person_nationality', [$data['nationalities']]); + } + + public function applyOn() + { + return 'person'; + } + + public function buildForm(FormBuilderInterface $builder) + { + $builder->add('nationalities', Select2CountryType::class, [ + 'placeholder' => 'Choose countries', + ]); + } + + public function describeAction($data, $format = 'string') + { + $countries = $data['nationalities']; + + $names = array_map(function (Country $c) { + return $this->translatableStringHelper->localize($c->getName()); + }, [$countries]); + + return [ + 'Filtered by nationality : %nationalities%', + ['%nationalities%' => implode(', ', $names)], + ]; } public function getTitle() @@ -90,22 +84,11 @@ class NationalityFilter implements FilterInterface, return "Filter by person's nationality"; } - public function addRole() + public function validateForm($data, ExecutionContextInterface $context) { - return NULL; - } - - public function describeAction($data, $format = 'string') - { - $countries = $data['nationalities']; - - $names = array_map(function(Country $c) { - return $this->translatableStringHelper->localize($c->getName()); - }, array($countries)); - - return array( - "Filtered by nationality : %nationalities%", - array('%nationalities%' => implode(", ", $names)) - ); + if (null === $data['nationalities']) { + $context->buildViolation('A nationality must be selected') + ->addViolation(); + } } } diff --git a/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php b/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php index b4c146960..6b2b3e171 100644 --- a/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php +++ b/src/Bundle/ChillPersonBundle/Form/AccompanyingPeriodType.php @@ -1,25 +1,29 @@ config = $config; } - - /** - * @param FormBuilderInterface $builder - * @param array $options - */ + public function buildForm(FormBuilderInterface $builder, array $options) { //if the period_action is close, date opening should not be seen - if ($options['period_action'] !== 'close') { + if ('close' !== $options['period_action']) { $builder ->add('openingDate', DateType::class, [ - "required" => true, - 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy' - ]) - ; + 'required' => true, + 'widget' => 'single_text', + 'format' => 'dd-MM-yyyy', + ]); } - + // closingDate should be seen only if // period_action = close // OR ( period_action = update AND accompanying period is already closed ) $accompanyingPeriod = $options['data']; - + if ( - ($options['period_action'] === 'close') - OR - ($options['period_action'] === 'create') - OR - ($options['period_action'] === 'update' AND !$accompanyingPeriod->isOpen()) + ('close' === $options['period_action']) + or ('create' === $options['period_action']) + or ('update' === $options['period_action'] and !$accompanyingPeriod->isOpen()) ) { - $builder->add('closingDate', DateType::class, [ 'required' => true, 'widget' => 'single_text', - 'format' => 'dd-MM-yyyy' + 'format' => 'dd-MM-yyyy', ]); - + $builder->add('closingMotive', ClosingMotivePickerType::class); } - - if ($this->config['user'] === 'visible') { + + if ('visible' === $this->config['user']) { $builder->add('user', UserPickerType::class, [ 'center' => $options['center'], - 'role' => new Role(PersonVoter::SEE), + 'role' => new Role(PersonVoter::SEE), ]); } - $builder->add('remark', ChillTextareaType::class, [ - 'required' => false - ]); + $builder->add('remark', ChillTextareaType::class, [ + 'required' => false, + ]); + } + + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['action'] = $options['period_action']; } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ - 'data_class' => 'Chill\PersonBundle\Entity\AccompanyingPeriod' + 'data_class' => 'Chill\PersonBundle\Entity\AccompanyingPeriod', ]); $resolver @@ -107,18 +104,7 @@ class AccompanyingPeriodType extends AbstractType ->addAllowedTypes('period_action', 'string') ->addAllowedValues('period_action', ['update', 'open', 'close', 'create']) ->setRequired('center') - ->setAllowedTypes('center', Center::class) - ; - } - - /** - * @param FormView $view - * @param FormInterface $form - * @param array $options - */ - public function buildView(FormView $view, FormInterface $form, array $options) - { - $view->vars['action'] = $options['period_action']; + ->setAllowedTypes('center', Center::class); } /** diff --git a/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php b/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php index b1cdfee7a..c916ff740 100644 --- a/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php +++ b/src/Bundle/ChillPersonBundle/Form/ChoiceLoader/PersonChoiceLoader.php @@ -1,68 +1,123 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Form\ChoiceLoader; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; -use Doctrine\ORM\EntityRepository; use Chill\PersonBundle\Entity\Person; +use Doctrine\ORM\EntityRepository; +use RuntimeException; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; +use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; + +use function call_user_func; +use function in_array; /** - * Class PersonChoiceLoader - * - * @package Chill\PersonBundle\Form\ChoiceLoader - * @author Julien Fastré + * Class PersonChoiceLoader. */ class PersonChoiceLoader implements ChoiceLoaderInterface { /** - * @var EntityRepository + * @var array */ - protected $personRepository; - + protected $centers = []; + /** * @var array */ protected $lazyLoadedPersons = []; - + /** - * @var array + * @var EntityRepository */ - protected $centers = []; - + protected $personRepository; + /** * PersonChoiceLoader constructor. - * - * @param EntityRepository $personRepository - * @param array|null $centers */ public function __construct( EntityRepository $personRepository, - array $centers = null + ?array $centers = null ) { $this->personRepository = $personRepository; - if (NULL !== $centers) { + + if (null !== $centers) { $this->centers = $centers; } } - + + /** + * @param null $value + */ + public function loadChoiceList($value = null): ChoiceListInterface + { + return new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( + $this->lazyLoadedPersons, + function (Person $p) use ($value) { + return call_user_func($value, $p); + } + ); + } + + /** + * @param null $value + * + * @return array + */ + public function loadChoicesForValues(array $values, $value = null) + { + $choices = []; + + foreach ($values as $value) { + if (empty($value)) { + continue; + } + + $person = $this->personRepository->find($value); + + if ( + $this->hasCenterFilter() + && !in_array($person->getCenter(), $this->centers) + ) { + throw new RuntimeException('chosen a person not in correct center'); + } + + $choices[] = $person; + } + + return $choices; + } + + /** + * @param null $value + * + * @return array|string[] + */ + public function loadValuesForChoices(array $choices, $value = null) + { + $values = []; + + foreach ($choices as $choice) { + if (null === $choice) { + $values[] = null; + + continue; + } + + $id = call_user_func($value, $choice); + $values[] = $id; + $this->lazyLoadedPersons[$id] = $choice; + } + + return $values; + } + /** * @return bool */ @@ -70,69 +125,4 @@ class PersonChoiceLoader implements ChoiceLoaderInterface { return count($this->centers) > 0; } - - /** - * @param null $value - * @return ChoiceListInterface - */ - public function loadChoiceList($value = null): ChoiceListInterface - { - $list = new \Symfony\Component\Form\ChoiceList\ArrayChoiceList( - $this->lazyLoadedPersons, - function(Person $p) use ($value) { - return \call_user_func($value, $p); - }); - - return $list; - } - - /** - * @param array $values - * @param null $value - * @return array - */ - public function loadChoicesForValues(array $values, $value = null) - { - $choices = []; - - foreach($values as $value) { - if (empty($value)) { - continue; - } - - $person = $this->personRepository->find($value); - - if ($this->hasCenterFilter() && - !\in_array($person->getCenter(), $this->centers)) { - throw new \RuntimeException("chosen a person not in correct center"); - } - - $choices[] = $person; - } - - return $choices; - } - - /** - * @param array $choices - * @param null $value - * @return array|string[] - */ - public function loadValuesForChoices(array $choices, $value = null) - { - $values = []; - - foreach ($choices as $choice) { - if (NULL === $choice) { - $values[] = null; - continue; - } - - $id = \call_user_func($value, $choice); - $values[] = $id; - $this->lazyLoadedPersons[$id] = $choice; - } - - return $values; - } } diff --git a/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php b/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php index 672fc4f19..ba8544cf0 100644 --- a/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php +++ b/src/Bundle/ChillPersonBundle/Form/ClosingMotiveType.php @@ -1,76 +1,55 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\PersonBundle\Form; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; -use Chill\PersonBundle\Form\Type\ClosingMotivePickerType; -use Chill\MainBundle\Form\Type\TranslatableStringFormType; -use Symfony\Component\Form\Extension\Core\Type\CheckboxType; -use Symfony\Component\Form\Extension\Core\Type\NumberType; /** - * Class ClosingMotiveType + * Chill is a software for social workers * - * @package Chill\PersonBundle\Form + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\PersonBundle\Form; + +use Chill\MainBundle\Form\Type\TranslatableStringFormType; +use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive; +use Chill\PersonBundle\Form\Type\ClosingMotivePickerType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +/** + * Class ClosingMotiveType. */ class ClosingMotiveType extends AbstractType { - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('name', TranslatableStringFormType::class, [ - 'label' => 'Nom' + 'label' => 'Nom', ]) ->add('active', CheckboxType::class, [ 'label' => 'Actif ?', - 'required' => false + 'required' => false, ]) ->add('ordering', NumberType::class, [ 'label' => 'Ordre d\'apparition', 'required' => true, - 'scale' => 5 + 'scale' => 5, ]) ->add('parent', ClosingMotivePickerType::class, [ 'label' => 'Parent', 'required' => false, 'placeholder' => 'closing_motive.any parent', 'multiple' => false, - 'only_leaf' => false - ]) - ; + 'only_leaf' => false, + ]); } - - /** - * @param OptionsResolver $resolver - */ + public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', ClosingMotive::class) - ; + ->setDefault('class', ClosingMotive::class); } } - \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php b/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php index ec3ddbf82..a94ee17b6 100644 --- a/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/CreationPersonType.php @@ -1,152 +1,134 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Form; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Chill\MainBundle\Form\Type\CenterType; -use Chill\PersonBundle\Form\Type\GenderType; use Chill\MainBundle\Form\Type\DataTransformer\CenterTransformer; use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; +use Chill\PersonBundle\Form\Type\GenderType; use Chill\PersonBundle\Form\Type\PersonAltNameType; +use DateTime; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; class CreationPersonType extends AbstractType { + public const FORM_BEING_REVIEWED = 'being_reviewed'; - const NAME = 'chill_personbundle_person_creation'; + public const FORM_NOT_REVIEWED = 'not_reviewed'; - const FORM_NOT_REVIEWED = 'not_reviewed'; - const FORM_REVIEWED = 'reviewed' ; - const FORM_BEING_REVIEWED = 'being_reviewed'; + public const FORM_REVIEWED = 'reviewed'; + + public const NAME = 'chill_personbundle_person_creation'; /** - * - * @var CenterTransformer - */ - private $centerTransformer; - - /** - * * @var ConfigPersonAltNamesHelper */ protected $configPersonAltNamesHelper; + /** + * @var CenterTransformer + */ + private $centerTransformer; + public function __construct( CenterTransformer $centerTransformer, ConfigPersonAltNamesHelper $configPersonAltNamesHelper - ) { + ) { $this->centerTransformer = $centerTransformer; $this->configPersonAltNamesHelper = $configPersonAltNamesHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { - if ($options['form_status'] === self::FORM_BEING_REVIEWED) { - + if (self::FORM_BEING_REVIEWED === $options['form_status']) { $dateToStringTransformer = new DateTimeToStringTransformer( - null, null, 'd-m-Y', false); + null, + null, + 'd-m-Y', + false + ); $builder->add('firstName', HiddenType::class) - ->add('lastName', HiddenType::class) - ->add('birthdate', HiddenType::class, array( - 'property_path' => 'birthdate' - )) - ->add('gender', HiddenType::class) - ->add('creation_date', HiddenType::class, array( - 'mapped' => false - )) - ->add('form_status', HiddenType::class, array( - 'mapped' => false, - 'data' => $options['form_status'] - )) - ->add('center', HiddenType::class) - ; - + ->add('lastName', HiddenType::class) + ->add('birthdate', HiddenType::class, [ + 'property_path' => 'birthdate', + ]) + ->add('gender', HiddenType::class) + ->add('creation_date', HiddenType::class, [ + 'mapped' => false, + ]) + ->add('form_status', HiddenType::class, [ + 'mapped' => false, + 'data' => $options['form_status'], + ]) + ->add('center', HiddenType::class); + if ($this->configPersonAltNamesHelper->hasAltNames()) { - $builder->add('altNames', PersonAltNameType::class, [ - 'by_reference' => false, - 'force_hidden' => true + $builder->add('altNames', PersonAltNameType::class, [ + 'by_reference' => false, + 'force_hidden' => true, ]); } - + $builder->get('birthdate') - ->addModelTransformer($dateToStringTransformer); + ->addModelTransformer($dateToStringTransformer); $builder->get('creation_date') - ->addModelTransformer($dateToStringTransformer); + ->addModelTransformer($dateToStringTransformer); $builder->get('center') - ->addModelTransformer($this->centerTransformer); + ->addModelTransformer($this->centerTransformer); } else { $builder ->add('firstName') ->add('lastName') - ->add('birthdate', DateType::class, array('required' => false, - 'widget' => 'single_text', 'format' => 'dd-MM-yyyy')) - ->add('gender', GenderType::class, array( - 'required' => true, 'placeholder' => null - )) - ->add('creation_date', DateType::class, array( + ->add('birthdate', DateType::class, ['required' => false, + 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', ]) + ->add('gender', GenderType::class, [ + 'required' => true, 'placeholder' => null, + ]) + ->add('creation_date', DateType::class, [ 'required' => true, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy', 'mapped' => false, - 'data' => new \DateTime())) - ->add('form_status', HiddenType::class, array( + 'data' => new DateTime(), ]) + ->add('form_status', HiddenType::class, [ 'data' => $options['form_status'], - 'mapped' => false - )) - ->add('center', CenterType::class) - ; - + 'mapped' => false, + ]) + ->add('center', CenterType::class); + if ($this->configPersonAltNamesHelper->hasAltNames()) { - $builder->add('altNames', PersonAltNameType::class, [ - 'by_reference' => false + $builder->add('altNames', PersonAltNameType::class, [ + 'by_reference' => false, ]); } } } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\PersonBundle\Entity\Person' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\PersonBundle\Entity\Person', + ]); $resolver->setRequired('form_status') - ->setAllowedValues('form_status', array( - self::FORM_BEING_REVIEWED, - self::FORM_NOT_REVIEWED, - self::FORM_REVIEWED - )); + ->setAllowedValues('form_status', [ + self::FORM_BEING_REVIEWED, + self::FORM_NOT_REVIEWED, + self::FORM_REVIEWED, + ]); } /** diff --git a/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php b/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php index d1f50404b..5545c0a14 100644 --- a/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php +++ b/src/Bundle/ChillPersonBundle/Form/DataMapper/PersonAltNameDataMapper.php @@ -1,17 +1,22 @@ getIterator() as $key => $altName) { /** @var PersonAltName $altName */ $mapIndexToKey[$altName->getKey()] = $key; } - + foreach ($forms as $key => $form) { - if (\array_key_exists($key, $mapIndexToKey)) { + if (array_key_exists($key, $mapIndexToKey)) { $form->setData($viewData->get($mapIndexToKey[$key])->getLabel()); } } } /** - * * @param FormInterface[] $forms * @param Collection $viewData */ @@ -52,16 +57,16 @@ class PersonAltNameDataMapper implements DataMapperInterface $dataIterator = $viewData instanceof ArrayCollection ? $viewData->toArray() : $viewData->getIterator(); } - + foreach ($dataIterator as $key => $altName) { /** @var PersonAltName $altName */ $mapIndexToKey[$altName->getKey()] = $key; } - + foreach ($forms as $key => $form) { $isEmpty = empty($form->getData()); - - if (\array_key_exists($key, $mapIndexToKey)) { + + if (array_key_exists($key, $mapIndexToKey)) { if ($isEmpty) { $viewData->remove($mapIndexToKey[$key]); } else { @@ -71,8 +76,7 @@ class PersonAltNameDataMapper implements DataMapperInterface if (!$isEmpty) { $altName = (new PersonAltName()) ->setKey($key) - ->setLabel($form->getData()) - ; + ->setLabel($form->getData()); if (is_array($viewData)) { $viewData[] = $altName; @@ -82,6 +86,5 @@ class PersonAltNameDataMapper implements DataMapperInterface } } } - } } diff --git a/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonToIdTransformer.php b/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonToIdTransformer.php index 2561019d5..0198b3b8d 100644 --- a/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonToIdTransformer.php +++ b/src/Bundle/ChillPersonBundle/Form/DataTransformer/PersonToIdTransformer.php @@ -1,11 +1,18 @@ om = $om; } - /** - * Transforms an object (issue) to a string (id). - * - * @param Person|null $issue - * @return string - */ - public function transform($issue) - { - if (null === $issue) { - return ""; - } - - return $issue->getId(); - } - /** * Transforms a string (id) to an object (issue). * * @param string $id * - * @return Person|null - * * @throws TransformationFailedException if object (issue) is not found. + * + * @return Person|null */ public function reverseTransform($id) { @@ -54,8 +43,7 @@ class PersonToIdTransformer implements DataTransformerInterface $issue = $this->om ->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('id' => $id)) - ; + ->findOneBy(['id' => $id]); if (null === $issue) { throw new TransformationFailedException(sprintf( @@ -66,5 +54,20 @@ class PersonToIdTransformer implements DataTransformerInterface return $issue; } + + /** + * Transforms an object (issue) to a string (id). + * + * @param Person|null $issue + * + * @return string + */ + public function transform($issue) + { + if (null === $issue) { + return ''; + } + + return $issue->getId(); + } } -?> \ No newline at end of file diff --git a/src/Bundle/ChillPersonBundle/Form/MaritalStatusType.php b/src/Bundle/ChillPersonBundle/Form/MaritalStatusType.php index 1897c7dc4..2387daa9f 100644 --- a/src/Bundle/ChillPersonBundle/Form/MaritalStatusType.php +++ b/src/Bundle/ChillPersonBundle/Form/MaritalStatusType.php @@ -1,45 +1,40 @@ add('id', TextType::class, [ - 'label' => 'Identifiant' + 'label' => 'Identifiant', ]) ->add('name', TranslatableStringFormType::class, [ - 'label' => 'Nom' - ]) - ; + 'label' => 'Nom', + ]); } - - /** - * @param OptionsResolver $resolver - */ + public function configureOptions(OptionsResolver $resolver) { $resolver - ->setDefault('class', MaritalStatus::class) - ; + ->setDefault('class', MaritalStatus::class); } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Form/PersonConfimDuplicateType.php b/src/Bundle/ChillPersonBundle/Form/PersonConfimDuplicateType.php index fd7fa3e50..82fb5d3a9 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonConfimDuplicateType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonConfimDuplicateType.php @@ -1,5 +1,12 @@ add('confirm', CheckboxType::class, [ - 'label' => 'I confirm the merger of these 2 people', - 'mapped' => false, - ]); + ->add('confirm', CheckboxType::class, [ + 'label' => 'I confirm the merger of these 2 people', + 'mapped' => false, + ]); } /** diff --git a/src/Bundle/ChillPersonBundle/Form/PersonFindManuallyDuplicateType.php b/src/Bundle/ChillPersonBundle/Form/PersonFindManuallyDuplicateType.php index c46f2cf82..e0d828c07 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonFindManuallyDuplicateType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonFindManuallyDuplicateType.php @@ -1,19 +1,21 @@ add('direction', HiddenType::class, [ 'data' => 'starting', - ]) - ; + ]); } /** diff --git a/src/Bundle/ChillPersonBundle/Form/PersonType.php b/src/Bundle/ChillPersonBundle/Form/PersonType.php index 35697b617..9325cef2d 100644 --- a/src/Bundle/ChillPersonBundle/Form/PersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/PersonType.php @@ -1,22 +1,10 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Form; @@ -27,10 +15,10 @@ use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\Select2CountryType; use Chill\MainBundle\Form\Type\Select2LanguageType; use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; +use Chill\PersonBundle\Entity\PersonPhone; use Chill\PersonBundle\Form\Type\GenderType; use Chill\PersonBundle\Form\Type\PersonAltNameType; use Chill\PersonBundle\Form\Type\PersonPhoneType; -use Chill\PersonBundle\Entity\PersonPhone; use Chill\PersonBundle\Form\Type\Select2MaritalStatusType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\DateType; @@ -50,16 +38,14 @@ class PersonType extends AbstractType * * @var string[] */ - protected $config = array(); + protected $config = []; /** - * * @var ConfigPersonAltNamesHelper */ protected $configAltNamesHelper; /** - * * @param string[] $personFieldsConfiguration configuration of visibility of some fields */ public function __construct( @@ -70,46 +56,41 @@ class PersonType extends AbstractType $this->configAltNamesHelper = $configAltNamesHelper; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('firstName') ->add('lastName') - ->add('birthdate', DateType::class, array('required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy')) - ->add('gender', GenderType::class, array( - 'required' => true - )); + ->add('birthdate', DateType::class, ['required' => false, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy']) + ->add('gender', GenderType::class, [ + 'required' => true, + ]); if ($this->configAltNamesHelper->hasAltNames()) { $builder->add('altNames', PersonAltNameType::class, [ - 'by_reference' => false + 'by_reference' => false, ]); } - if ($this->config['memo'] === 'visible') { + if ('visible' === $this->config['memo']) { $builder - ->add('memo', ChillTextareaType::class, array('required' => false)) - ; + ->add('memo', ChillTextareaType::class, ['required' => false]); } - if ($this->config['place_of_birth'] === 'visible') { - $builder->add('placeOfBirth', TextType::class, array('required' => false)); + if ('visible' === $this->config['place_of_birth']) { + $builder->add('placeOfBirth', TextType::class, ['required' => false]); } - if ($this->config['contact_info'] === 'visible') { - $builder->add('contactInfo', ChillTextareaType::class, array('required' => false)); + if ('visible' === $this->config['contact_info']) { + $builder->add('contactInfo', ChillTextareaType::class, ['required' => false]); } - if ($this->config['phonenumber'] === 'visible') { - $builder->add('phonenumber', TelType::class, array('required' => false)); + if ('visible' === $this->config['phonenumber']) { + $builder->add('phonenumber', TelType::class, ['required' => false]); } - if ($this->config['mobilenumber'] === 'visible') { - $builder->add('mobilenumber', TelType::class, array('required' => false)); + if ('visible' === $this->config['mobilenumber']) { + $builder->add('mobilenumber', TelType::class, ['required' => false]); } $builder->add('otherPhoneNumbers', ChillCollectionType::class, [ @@ -121,46 +102,48 @@ class PersonType extends AbstractType 'allow_delete' => true, 'by_reference' => false, 'label' => false, - 'delete_empty' => function(PersonPhone $pp = null) { - return NULL === $pp || $pp->isEmpty(); + 'delete_empty' => function (?PersonPhone $pp = null) { + return null === $pp || $pp->isEmpty(); }, - 'error_bubbling' => false + 'error_bubbling' => false, ]); - if ($this->config['email'] === 'visible') { - $builder->add('email', EmailType::class, array('required' => false)); + if ('visible' === $this->config['email']) { + $builder->add('email', EmailType::class, ['required' => false]); } - if ($this->config['country_of_birth'] === 'visible') { - $builder->add('countryOfBirth', Select2CountryType::class, array( - 'required' => false - )); - } - - if ($this->config['nationality'] === 'visible') { - $builder->add('nationality', Select2CountryType::class, array( - 'required' => false - )); - } - - if ($this->config['spoken_languages'] === 'visible') { - $builder->add('spokenLanguages', Select2LanguageType::class, array( + if ('visible' === $this->config['country_of_birth']) { + $builder->add('countryOfBirth', Select2CountryType::class, [ 'required' => false, - 'multiple' => true - )); + ]); } - if ($this->config['marital_status'] === 'visible'){ - $builder->add('maritalStatus', Select2MaritalStatusType::class, array( - 'required' => false - )); + if ('visible' === $this->config['nationality']) { + $builder->add('nationality', Select2CountryType::class, [ + 'required' => false, + ]); } - if($options['cFGroup']) { + if ('visible' === $this->config['spoken_languages']) { + $builder->add('spokenLanguages', Select2LanguageType::class, [ + 'required' => false, + 'multiple' => true, + ]); + } + + if ('visible' === $this->config['marital_status']) { + $builder->add('maritalStatus', Select2MaritalStatusType::class, [ + 'required' => false, + ]); + } + + if ($options['cFGroup']) { $builder - ->add('cFData', CustomFieldType::class, - array('attr' => array('class' => 'cf-fields'), 'group' => $options['cFGroup'])) - ; + ->add( + 'cFData', + CustomFieldType::class, + ['attr' => ['class' => 'cf-fields'], 'group' => $options['cFGroup']] + ); } } @@ -169,17 +152,18 @@ class PersonType extends AbstractType */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => 'Chill\PersonBundle\Entity\Person', - 'validation_groups' => array('general', 'creation'), - )); + 'validation_groups' => ['general', 'creation'], + ]); - $resolver->setRequired(array( - 'cFGroup' - )); + $resolver->setRequired([ + 'cFGroup', + ]); $resolver->setAllowedTypes( - 'cFGroup', array('null', 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup') + 'cFGroup', + ['null', 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup'] ); } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php b/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php index d2f85c924..5f209e8a7 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/ClosingMotivePickerType.php @@ -1,32 +1,29 @@ entityRenderExtension = $chillEntityRenderExtension; $this->repository = $closingMotiveRepository; } - + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'class' => ClosingMotive::class, + 'empty_data' => null, + 'placeholder' => 'Choose a motive', + 'choice_label' => function (ClosingMotive $cm) { + return $this->entityRenderExtension->renderString($cm); + }, + 'only_leaf' => true, + ]); + + $resolver + ->setAllowedTypes('only_leaf', 'bool') + ->setNormalizer('choices', function (Options $options) { + return $this->repository + ->getActiveClosingMotive($options['only_leaf']); + }); + } + /** * @return string */ @@ -61,38 +79,12 @@ class ClosingMotivePickerType extends AbstractType { return 'closing_motive'; } - + /** - * @return null|string + * @return string|null */ public function getParent() { return EntityType::class; } - - /** - * @param OptionsResolver $resolver - */ - public function configureOptions(OptionsResolver $resolver) - { - - $resolver->setDefaults([ - 'class' => ClosingMotive::class, - 'empty_data' => null, - 'placeholder' => 'Choose a motive', - 'choice_label' => function(ClosingMotive $cm) { - return $this->entityRenderExtension->renderString($cm); - }, - 'only_leaf' => true - ]); - - $resolver - ->setAllowedTypes('only_leaf', 'bool') - ->setNormalizer('choices', function (Options $options) { - return $this->repository - ->getActiveClosingMotive($options['only_leaf']); - }) - ; - } - } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php b/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php index bdd31e899..96ec16ea5 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/GenderType.php @@ -1,38 +1,42 @@ Person::MALE_GENDER, Person::FEMALE_GENDER => Person::FEMALE_GENDER, - Person::BOTH_GENDER => Person::BOTH_GENDER - ); + Person::BOTH_GENDER => Person::BOTH_GENDER, + ]; - $resolver->setDefaults(array( + $resolver->setDefaults([ 'choices' => $a, 'expanded' => true, 'multiple' => false, - 'placeholder' => null - )); + 'placeholder' => null, + ]); } + public function getParent() + { + return ChoiceType::class; + } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PersonAltNameType.php b/src/Bundle/ChillPersonBundle/Form/Type/PersonAltNameType.php index 1ba58e86e..5e0b7e14e 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/PersonAltNameType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/PersonAltNameType.php @@ -1,35 +1,36 @@ configHelper = $configHelper; @@ -40,28 +41,17 @@ class PersonAltNameType extends AbstractType { foreach ($this->getKeyChoices() as $label => $key) { $builder->add( - $key, - $options['force_hidden'] ? HiddenType::class : TextType::class, [ - 'label' => $label, - 'required' => false - ]); + $key, + $options['force_hidden'] ? HiddenType::class : TextType::class, + [ + 'label' => $label, + 'required' => false, + ] + ); } - + $builder->setDataMapper(new \Chill\PersonBundle\Form\DataMapper\PersonAltNameDataMapper()); } - - protected function getKeyChoices() - { - $choices = $this->configHelper->getChoices(); - $translatedChoices = []; - - foreach ($choices as $key => $labels) { - $label = $this->translatableStringHelper->localize($labels); - $translatedChoices[$label] = $key; - } - - return $translatedChoices; - } public function configureOptions(OptionsResolver $resolver) { @@ -69,8 +59,19 @@ class PersonAltNameType extends AbstractType ->setDefault('class', \Chill\PersonBundle\Entity\PersonAltName::class) ->setDefined('force_hidden') ->setAllowedTypes('force_hidden', 'bool') - ->setDefault('force_hidden', false) - ; + ->setDefault('force_hidden', false); } + protected function getKeyChoices() + { + $choices = $this->configHelper->getChoices(); + $translatedChoices = []; + + foreach ($choices as $key => $labels) { + $label = $this->translatableStringHelper->localize($labels); + $translatedChoices[$label] = $key; + } + + return $translatedChoices; + } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php b/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php index f06d5cd72..8150551c9 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php @@ -1,5 +1,12 @@ phonenumberHelper = $phonenumberHelper; @@ -38,11 +43,11 @@ class PersonPhoneType extends AbstractType 'required' => false, ]); - $builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) { - if (NULL === $event->getData()) { + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { + if (null === $event->getData()) { return; } - + $oldPersonPhone = $this->em->getUnitOfWork() ->getOriginalEntityData($event->getData()); @@ -59,7 +64,6 @@ class PersonPhoneType extends AbstractType ->setDefaults([ 'data_class' => PersonPhone::class, 'validation_groups' => ['general', 'creation'], - ]) - ; + ]); } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php b/src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php index 839c84b69..097bd7b42 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/PickPersonType.php @@ -1,41 +1,31 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Form\Type; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\GroupCenter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Form\ChoiceLoader\PersonChoiceLoader; +use Chill\PersonBundle\Repository\PersonRepository; +use Chill\PersonBundle\Search\PersonSearch; +use RuntimeException; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Chill\MainBundle\Entity\GroupCenter; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\MainBundle\Entity\Center; -use Chill\PersonBundle\Repository\PersonRepository; -use Chill\PersonBundle\Search\PersonSearch; use Symfony\Component\Translation\TranslatorInterface; -use Chill\PersonBundle\Form\ChoiceLoader\PersonChoiceLoader; -use Symfony\Component\OptionsResolver\Options; /** * This type allow to pick a person. @@ -49,49 +39,41 @@ use Symfony\Component\OptionsResolver\Options; * `Chill\MainBundle\Entity\Center`. By default, all the reachable centers as selected. * - with the `role` option, only the people belonging to the reachable center for the * given role are displayed. - * - * - * @author Julien Fastré */ class PickPersonType extends AbstractType { /** - * @var PersonRepository - */ - protected $personRepository; - - /** - * - * @var \Chill\MainBundle\Entity\User - */ - protected $user; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + /** - * - * @var UrlGeneratorInterface + * @var PersonRepository */ - protected $urlGenerator; - + protected $personRepository; + /** - * * @var TranslatorInterface */ protected $translator; + /** + * @var UrlGeneratorInterface + */ + protected $urlGenerator; + + /** + * @var \Chill\MainBundle\Entity\User + */ + protected $user; + public function __construct( - PersonRepository $personRepository, - TokenStorageInterface $tokenStorage, - AuthorizationHelper $authorizationHelper, - UrlGeneratorInterface $urlGenerator, - TranslatorInterface $translator - ) - { + PersonRepository $personRepository, + TokenStorageInterface $tokenStorage, + AuthorizationHelper $authorizationHelper, + UrlGeneratorInterface $urlGenerator, + TranslatorInterface $translator + ) { $this->personRepository = $personRepository; $this->user = $tokenStorage->getToken()->getUser(); $this->authorizationHelper = $authorizationHelper; @@ -99,42 +81,16 @@ class PickPersonType extends AbstractType $this->translator = $translator; } - protected function filterCentersfom(Options $options) + public function buildView(\Symfony\Component\Form\FormView $view, \Symfony\Component\Form\FormInterface $form, array $options) { - if ($options['role'] === NULL) { - $centers = array_map(function (GroupCenter $g) { - - return $g->getCenter(); - }, $this->user->getGroupCenters()->toArray()); - } else { - $centers = $this->authorizationHelper - ->getReachableCenters($this->user, $options['role']); - } - - if ($options['centers'] === NULL) { - // we select all selected centers - $selectedCenters = $centers; - } else { - $selectedCenters = array(); - $optionsCenters = is_array($options['centers']) ? - $options['centers'] : array($options['centers']); - - foreach ($optionsCenters as $c) { - // check that every member of the array is a center - if (!$c instanceof Center) { - throw new \RuntimeException('Every member of the "centers" ' - . 'option must be an instance of '.Center::class); - } - if (!in_array($c->getId(), array_map( - function(Center $c) { return $c->getId();}, - $centers))) { - throw new AccessDeniedException('The given center is not reachable'); - } - $selectedCenters[] = $c; - } - } - - return $selectedCenters; + $view->vars['attr']['data-person-picker'] = true; + $view->vars['attr']['data-select-interactive-loading'] = true; + $view->vars['attr']['data-search-url'] = $this->urlGenerator + ->generate('chill_main_search', ['name' => PersonSearch::NAME, '_format' => 'json']); + $view->vars['attr']['data-placeholder'] = $this->translator->trans($options['placeholder']); + $view->vars['attr']['data-no-results-label'] = $this->translator->trans('select2.no_results'); + $view->vars['attr']['data-error-load-label'] = $this->translator->trans('select2.error_loading'); + $view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching'); } public function configureOptions(OptionsResolver $resolver) @@ -143,49 +99,78 @@ class PickPersonType extends AbstractType // add the possibles options for this type $resolver->setDefined('centers') - ->addAllowedTypes('centers', array('array', Center::class, 'null')) - ->setDefault('centers', null) - ->setDefined('role') - ->addAllowedTypes('role', array(Role::class, 'null')) - ->setDefault('role', null) - ; + ->addAllowedTypes('centers', ['array', Center::class, 'null']) + ->setDefault('centers', null) + ->setDefined('role') + ->addAllowedTypes('role', [Role::class, 'null']) + ->setDefault('role', null); // add the default options - $resolver->setDefaults(array( + $resolver->setDefaults([ 'class' => Person::class, - 'choice_label' => function(Person $p) { - return $p->getFirstname().' '.$p->getLastname(); + 'choice_label' => function (Person $p) { + return $p->getFirstname() . ' ' . $p->getLastname(); }, 'placeholder' => 'Pick a person', - 'choice_attr' => function(Person $p) { - return array( - 'data-center' => $p->getCenter()->getId() - ); + 'choice_attr' => function (Person $p) { + return [ + 'data-center' => $p->getCenter()->getId(), + ]; }, - 'attr' => array('class' => 'select2 '), - 'choice_loader' => function(Options $options) { + 'attr' => ['class' => 'select2 '], + 'choice_loader' => function (Options $options) { $centers = $this->filterCentersfom($options); - + return new PersonChoiceLoader($this->personRepository, $centers); - } - )); + }, + ]); } public function getParent() { return EntityType::class; } - - public function buildView(\Symfony\Component\Form\FormView $view, \Symfony\Component\Form\FormInterface $form, array $options) - { - $view->vars['attr']['data-person-picker'] = true; - $view->vars['attr']['data-select-interactive-loading'] = true; - $view->vars['attr']['data-search-url'] = $this->urlGenerator - ->generate('chill_main_search', [ 'name' => PersonSearch::NAME, '_format' => 'json' ]); - $view->vars['attr']['data-placeholder'] = $this->translator->trans($options['placeholder']); - $view->vars['attr']['data-no-results-label'] = $this->translator->trans('select2.no_results'); - $view->vars['attr']['data-error-load-label'] = $this->translator->trans('select2.error_loading'); - $view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching'); - } + protected function filterCentersfom(Options $options) + { + if (null === $options['role']) { + $centers = array_map(function (GroupCenter $g) { + return $g->getCenter(); + }, $this->user->getGroupCenters()->toArray()); + } else { + $centers = $this->authorizationHelper + ->getReachableCenters($this->user, $options['role']); + } + + if (null === $options['centers']) { + // we select all selected centers + $selectedCenters = $centers; + } else { + $selectedCenters = []; + $optionsCenters = is_array($options['centers']) ? + $options['centers'] : [$options['centers']]; + + foreach ($optionsCenters as $c) { + // check that every member of the array is a center + if (!$c instanceof Center) { + throw new RuntimeException('Every member of the "centers" ' + . 'option must be an instance of ' . Center::class); + } + + if ( + !in_array($c->getId(), array_map( + function (Center $c) { + return $c->getId(); + }, + $centers + )) + ) { + throw new AccessDeniedException('The given center is not reachable'); + } + $selectedCenters[] = $c; + } + } + + return $selectedCenters; + } } diff --git a/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php b/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php index 0cff8ee51..d269036e6 100644 --- a/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php +++ b/src/Bundle/ChillPersonBundle/Form/Type/Select2MaritalStatusType.php @@ -1,63 +1,46 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Form\Type; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\OptionsResolver\OptionsResolver; use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer; +use Chill\MainBundle\Form\Type\Select2ChoiceType; +use Doctrine\Persistence\ObjectManager; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\HttpFoundation\RequestStack; -use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\Form\Type\Select2ChoiceType; +use Symfony\Component\OptionsResolver\OptionsResolver; /** - * A type to select the marital status - * - * @author Champs-Libres COOP + * A type to select the marital status. */ class Select2MaritalStatusType extends AbstractType { - /** @var RequestStack */ - private $requestStack; - - /** @var ObjectManager */ + /** + * @var ObjectManager + */ private $em; - public function __construct(RequestStack $requestStack,ObjectManager $em) + /** + * @var RequestStack + */ + private $requestStack; + + public function __construct(RequestStack $requestStack, ObjectManager $em) { $this->requestStack = $requestStack; $this->em = $em; } - public function getBlockPrefix() { - return 'select2_chill_marital_status'; - } - - public function getParent() { - return Select2ChoiceType::class; - } - public function buildForm(FormBuilderInterface $builder, array $options) { - $transformer = new ObjectToIdTransformer($this->em,'Chill\PersonBundle\Entity\MaritalStatus'); + $transformer = new ObjectToIdTransformer($this->em, 'Chill\PersonBundle\Entity\MaritalStatus'); $builder->addModelTransformer($transformer); } @@ -65,7 +48,7 @@ class Select2MaritalStatusType extends AbstractType { $locale = $this->requestStack->getCurrentRequest()->getLocale(); $maritalStatuses = $this->em->getRepository('Chill\PersonBundle\Entity\MaritalStatus')->findAll(); - $choices = array(); + $choices = []; foreach ($maritalStatuses as $ms) { $choices[$ms->getId()] = $ms->getName()[$locale]; @@ -73,9 +56,19 @@ class Select2MaritalStatusType extends AbstractType asort($choices, SORT_STRING | SORT_FLAG_CASE); - $resolver->setDefaults(array( - 'class' => 'Chill\PersonBundle\Entity\MaritalStatus', - 'choices' => array_combine(array_values($choices),array_keys($choices)) - )); + $resolver->setDefaults([ + 'class' => 'Chill\PersonBundle\Entity\MaritalStatus', + 'choices' => array_combine(array_values($choices), array_keys($choices)), + ]); + } + + public function getBlockPrefix() + { + return 'select2_chill_marital_status'; + } + + public function getParent() + { + return Select2ChoiceType::class; } } diff --git a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php index 74052e87c..e81391412 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AccompanyingCourseMenuBuilder.php @@ -1,5 +1,12 @@ translator = $translator; } - - public static function getMenuIds(): array - { - return [ 'accompanyingCourse' ]; - } - + public function buildMenu($menuId, MenuItem $menu, array $parameters): void { $menu->addChild($this->translator->trans('Resume Accompanying Course'), [ 'route' => 'chill_person_accompanying_course_index', 'routeParameters' => [ - 'accompanying_period_id' => $parameters['accompanyingCourse']->getId() - ]]) - ->setExtras(['order' => 10]); - + 'accompanying_period_id' => $parameters['accompanyingCourse']->getId(), + ], ]) + ->setExtras(['order' => 10]); + $menu->addChild($this->translator->trans('Edit Accompanying Course'), [ 'route' => 'chill_person_accompanying_course_show', 'routeParameters' => [ - 'accompanying_period_id' => $parameters['accompanyingCourse']->getId() - ]]) - ->setExtras(['order' => 20]); + 'accompanying_period_id' => $parameters['accompanyingCourse']->getId(), + ], ]) + ->setExtras(['order' => 20]); $menu->addChild($this->translator->trans('Accompanying Course Details'), [ 'route' => 'chill_person_accompanying_course_history', 'routeParameters' => [ - 'accompanying_period_id' => $parameters['accompanyingCourse']->getId() - ]]) - ->setExtras(['order' => 30]); + 'accompanying_period_id' => $parameters['accompanyingCourse']->getId(), + ], ]) + ->setExtras(['order' => 30]); + } + + public static function getMenuIds(): array + { + return ['accompanyingCourse']; } - - } diff --git a/src/Bundle/ChillPersonBundle/Menu/AdminMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/AdminMenuBuilder.php index e8a73d2ab..57ee8d75d 100644 --- a/src/Bundle/ChillPersonBundle/Menu/AdminMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/AdminMenuBuilder.php @@ -1,61 +1,46 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -/** - * - * - */ class AdminMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + public function __construct(AuthorizationCheckerInterface $authorizationChecker) { $this->authorizationChecker = $authorizationChecker; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { if (!$this->authorizationChecker->isGranted('ROLE_ADMIN')) { return; } - + $menu->addChild('Person', [ - 'route' => 'chill_person_admin' - ]) + 'route' => 'chill_person_admin', + ]) ->setExtras([ - 'order' => 20 + 'order' => 20, ]); } public static function getMenuIds(): array { - return [ 'admin_section' ]; + return ['admin_section']; } } diff --git a/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php index b39b14254..6137d6f2d 100644 --- a/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php @@ -1,20 +1,12 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; @@ -23,27 +15,24 @@ use Symfony\Contracts\Translation\TranslatorInterface; /** * Add menu entrie to person menu. - * + * * Menu entries added : - * + * * - person details ; * - accompanying period (if `visible`) - * */ class PersonMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var string 'visible' or 'hidden' */ protected $showAccompanyingPeriod; - + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( $showAccompanyingPeriod, TranslatorInterface $translator @@ -51,44 +40,44 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface $this->showAccompanyingPeriod = $showAccompanyingPeriod; $this->translator = $translator; } - + public function buildMenu($menuId, MenuItem $menu, array $parameters) { $menu->addChild($this->translator->trans('Person details'), [ - 'route' => 'chill_person_view', - 'routeParameters' => [ - 'person_id' => $parameters['person']->getId() - ] - ]) + 'route' => 'chill_person_view', + 'routeParameters' => [ + 'person_id' => $parameters['person']->getId(), + ], + ]) ->setExtras([ - 'order' => 50 + 'order' => 50, ]); $menu->addChild($this->translator->trans('Person duplicate'), [ - 'route' => 'chill_person_duplicate_view', - 'routeParameters' => [ - 'person_id' => $parameters['person']->getId() - ] + 'route' => 'chill_person_duplicate_view', + 'routeParameters' => [ + 'person_id' => $parameters['person']->getId(), + ], ]) - ->setExtras([ - 'order' => 51 - ]); - - if ($this->showAccompanyingPeriod === 'visible') { + ->setExtras([ + 'order' => 51, + ]); + + if ('visible' === $this->showAccompanyingPeriod) { $menu->addChild($this->translator->trans('Accompanying period list'), [ - 'route' => 'chill_person_accompanying_period_list', - 'routeParameters' => [ - 'person_id' => $parameters['person']->getId() - ] - ]) + 'route' => 'chill_person_accompanying_period_list', + 'routeParameters' => [ + 'person_id' => $parameters['person']->getId(), + ], + ]) ->setExtras([ - 'order' => 100 + 'order' => 100, ]); } } public static function getMenuIds(): array { - return [ 'person' ]; + return ['person']; } } diff --git a/src/Bundle/ChillPersonBundle/Menu/SectionMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/SectionMenuBuilder.php index ea6a1d060..306aa77d5 100644 --- a/src/Bundle/ChillPersonBundle/Menu/SectionMenuBuilder.php +++ b/src/Bundle/ChillPersonBundle/Menu/SectionMenuBuilder.php @@ -1,35 +1,22 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\PersonBundle\Security\Authorization\PersonVoter; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Component\Translation\TranslatorInterface; /** - * Class SectionMenuBuilder - * - * @package Chill\PersonBundle\Menu - * @author Julien Fastré + * Class SectionMenuBuilder. */ class SectionMenuBuilder implements LocalMenuBuilderInterface { @@ -37,47 +24,39 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + /** * @var TranslatorInterface */ protected $translator; - + /** * SectionMenuBuilder constructor. - * - * @param AuthorizationCheckerInterface $authorizationChecker - * @param TranslatorInterface $translator */ public function __construct(AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator) { $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; } - + /** * @param $menuId - * @param MenuItem $menu - * @param array $parameters */ public function buildMenu($menuId, MenuItem $menu, array $parameters) { if ($this->authorizationChecker->isGranted(PersonVoter::CREATE)) { $menu->addChild($this->translator->trans('Add a person'), [ - 'route' => 'chill_person_new' - ]) + 'route' => 'chill_person_new', + ]) ->setExtras([ 'order' => 10, - 'icons' => [ 'plus' ] + 'icons' => ['plus'], ]); } } - - /** - * @return array - */ + public static function getMenuIds(): array { - return [ 'section' ]; + return ['section']; } } diff --git a/src/Bundle/ChillPersonBundle/Privacy/AccompanyingPeriodPrivacyEvent.php b/src/Bundle/ChillPersonBundle/Privacy/AccompanyingPeriodPrivacyEvent.php index e8610b4c1..a3decb69e 100644 --- a/src/Bundle/ChillPersonBundle/Privacy/AccompanyingPeriodPrivacyEvent.php +++ b/src/Bundle/ChillPersonBundle/Privacy/AccompanyingPeriodPrivacyEvent.php @@ -1,5 +1,12 @@ . */ -use Symfony\Component\EventDispatcher\Event; -use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Symfony\Component\EventDispatcher\Event; class AccompanyingPeriodPrivacyEvent extends Event { public const ACCOMPANYING_PERIOD_PRIVACY_EVENT = 'chill_person.accompanying_period_privacy_event'; - protected AccompanyingPeriod $period; - protected array $args; + protected AccompanyingPeriod $period; + public function __construct($period, $args = []) { $this->period = $period; $this->args = $args; } - public function getPeriod(): AccompanyingPeriod - { - return $this->period; - } - public function getArgs(): array { return $this->args; } + + public function getPeriod(): AccompanyingPeriod + { + return $this->period; + } } diff --git a/src/Bundle/ChillPersonBundle/Privacy/PrivacyEvent.php b/src/Bundle/ChillPersonBundle/Privacy/PrivacyEvent.php index 65304f96a..39595adbb 100644 --- a/src/Bundle/ChillPersonBundle/Privacy/PrivacyEvent.php +++ b/src/Bundle/ChillPersonBundle/Privacy/PrivacyEvent.php @@ -1,5 +1,12 @@ . */ -use Symfony\Component\EventDispatcher\Event; use Chill\PersonBundle\Entity\Person; +use Symfony\Component\EventDispatcher\Event; /** - * Class PrivacyEvent + * Class PrivacyEvent. * * Array $args expects arguments with the following keys: 'element_class', 'element_id', 'action' * By default, action is set to 'show' - * - * @package Chill\PersonBundle\Privacy */ class PrivacyEvent extends Event { - const PERSON_PRIVACY_EVENT = 'chill_person.privacy_event'; - - /** - * @var Person - */ - private $person; - + public const PERSON_PRIVACY_EVENT = 'chill_person.privacy_event'; + /** * @var array */ private $args; - + + /** + * @var Person + */ + private $person; + /** * @var array */ private $persons; - + /** * PrivacyEvent constructor. - * - * @param Person $person - * @param array $args */ - public function __construct(Person $person, array $args = array('action' => 'show')) + public function __construct(Person $person, array $args = ['action' => 'show']) { $this->person = $person; $this->args = $args; - $this->persons = array(); + $this->persons = []; } - - /** - * @return Person - */ - public function getPerson() - { - return $this->person; - } - - /** - * @param Person $person - */ + public function addPerson(Person $person) { $this->persons[] = $person; - + return $this; } - - /** - * @return array $persons - */ - public function getPersons() - { - return $this->persons; - } - - /** - * @return bool - */ - public function hasPersons() - { - return count($this->persons) >= 1; - } - + /** * @return array */ @@ -106,5 +81,28 @@ class PrivacyEvent extends Event { return $this->args; } - -} \ No newline at end of file + + /** + * @return Person + */ + public function getPerson() + { + return $this->person; + } + + /** + * @return array $persons + */ + public function getPersons() + { + return $this->persons; + } + + /** + * @return bool + */ + public function hasPersons() + { + return count($this->persons) >= 1; + } +} diff --git a/src/Bundle/ChillPersonBundle/Privacy/PrivacyEventSubscriber.php b/src/Bundle/ChillPersonBundle/Privacy/PrivacyEventSubscriber.php index c37fc67b2..0eba4d63c 100644 --- a/src/Bundle/ChillPersonBundle/Privacy/PrivacyEventSubscriber.php +++ b/src/Bundle/ChillPersonBundle/Privacy/PrivacyEventSubscriber.php @@ -1,5 +1,12 @@ . */ +use Chill\PersonBundle\Entity\Person; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent; + +use function array_map; class PrivacyEventSubscriber implements EventSubscriberInterface { - /** * @var LoggerInterface */ @@ -43,8 +50,6 @@ class PrivacyEventSubscriber implements EventSubscriberInterface /** * PrivacyEventSubscriber constructor. - * - * @param LoggerInterface $logger */ public function __construct(LoggerInterface $logger, TokenStorageInterface $token) { @@ -56,11 +61,11 @@ class PrivacyEventSubscriber implements EventSubscriberInterface { return [ PrivacyEvent::PERSON_PRIVACY_EVENT => [ - ['onPrivacyEvent'] + ['onPrivacyEvent'], ], AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT => [ - ['onAccompanyingPeriodPrivacyEvent'] - ] + ['onAccompanyingPeriodPrivacyEvent'], + ], ]; } @@ -69,11 +74,13 @@ class PrivacyEventSubscriber implements EventSubscriberInterface $involved = $this->getInvolved(); $involved['period_id'] = $event->getPeriod()->getId(); $involved['persons'] = $event->getPeriod()->getPersons() - ->map(function(Person $p) { return $p->getId(); }) + ->map(function (Person $p) { + return $p->getId(); + }) ->toArray(); $this->logger->notice( - "[Privacy Event] An accompanying period has been viewed", + '[Privacy Event] An accompanying period has been viewed', array_merge($involved, $event->getArgs()) ); } @@ -92,14 +99,16 @@ class PrivacyEventSubscriber implements EventSubscriberInterface $involved['person_id'] = $event->getPerson()->getId(); if ($event->hasPersons()) { - $involved['persons'] = \array_map( - function(Person $p) { return $p->getId(); }, + $involved['persons'] = array_map( + function (Person $p) { + return $p->getId(); + }, $event->getPersons() ); } $this->logger->notice( - "[Privacy Event] A Person Folder has been viewed", + '[Privacy Event] A Person Folder has been viewed', array_merge($involved, $event->getArgs()) ); } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php index fc8233d23..0941db57a 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/AccompanyingPeriodWorkGoalRepository.php @@ -1,5 +1,12 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; use Doctrine\ORM\EntityRepository; -use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query\ResultSetMappingBuilder; /** * Class ClosingMotiveRepository - * Entity repository for closing motives - * - * @package Chill\PersonBundle\Repository + * Entity repository for closing motives. */ class ClosingMotiveRepository extends EntityRepository { /** - * @param bool $onlyLeaf * @return mixed */ public function getActiveClosingMotive(bool $onlyLeaf = true) { $rsm = new ResultSetMappingBuilder($this->getEntityManager()); $rsm->addRootEntityFromClassMetadata($this->getClassName(), 'cm'); - - $sql = "SELECT ".(string) $rsm." + + $sql = 'SELECT ' . (string) $rsm . ' FROM chill_person_accompanying_period_closingmotive AS cm WHERE - active IS TRUE "; - + active IS TRUE '; + if ($onlyLeaf) { - $sql .= "AND cm.id NOT IN ( + $sql .= 'AND cm.id NOT IN ( SELECT DISTINCT parent_id FROM chill_person_accompanying_period_closingmotive WHERE parent_id IS NOT NULL - )"; + )'; } - - $sql .= " ORDER BY cm.ordering ASC"; - + + $sql .= ' ORDER BY cm.ordering ASC'; + return $this->_em ->createNativeQuery($sql, $rsm) - ->getResult() - ; + ->getResult(); } } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php index b41e77591..af1699312 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/CommentRepository.php @@ -1,23 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; @@ -38,5 +25,4 @@ class CommentRepository extends ServiceEntityRepository { parent::__construct($registry, Comment::class); } - } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php index 6a5b28901..71aa6fd38 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/OriginRepository.php @@ -1,23 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; @@ -38,5 +25,4 @@ class OriginRepository extends ServiceEntityRepository { parent::__construct($registry, Origin::class); } - } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php index 46eaaaaa0..f6030a905 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php @@ -1,23 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; @@ -27,10 +14,10 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; /** - * @method Resource|null find($id, $lockMode = null, $lockVersion = null) - * @method Resource|null findOneBy(array $criteria, array $orderBy = null) - * @method Resource[] findAll() - * @method Resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) + * @method resource|null find($id, $lockMode = null, $lockVersion = null) + * @method resource|null findOneBy(array $criteria, array $orderBy = null) + * @method resource[] findAll() + * @method resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ class ResourceRepository extends ServiceEntityRepository { @@ -38,5 +25,4 @@ class ResourceRepository extends ServiceEntityRepository { parent::__construct($registry, Resource::class); } - } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php index fbe957ecf..307c3cc42 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodParticipationRepository.php @@ -1,23 +1,10 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository; @@ -38,5 +25,4 @@ class AccompanyingPeriodParticipationRepository extends ServiceEntityRepository { parent::__construct($registry, AccompanyingPeriodParticipation::class); } - } diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php index fffb55ede..5ab436bcb 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriodRepository.php @@ -1,29 +1,15 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Chill\PersonBundle\Entity\Person; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php index feea6d44d..09f43df15 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdMembersRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?HouseholdMembers @@ -46,5 +53,5 @@ class HouseholdMembersRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php index 38522806c..576f45f1a 100644 --- a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdRepository.php @@ -1,5 +1,12 @@ getResult() ; } - */ + */ /* public function findOneBySomeField($value): ?Household @@ -46,5 +53,5 @@ class HouseholdRepository extends ServiceEntityRepository ->getOneOrNullResult() ; } - */ + */ } diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonAltNameRepository.php b/src/Bundle/ChillPersonBundle/Repository/PersonAltNameRepository.php index 315cee94f..4e5db1d59 100644 --- a/src/Bundle/ChillPersonBundle/Repository/PersonAltNameRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/PersonAltNameRepository.php @@ -1,9 +1,16 @@ createQueryBuilder('pnd'); $qb->select('pnd') - ->where('pnd.person1 = :person OR pnd.person2 = :person') - ; + ->where('pnd.person1 = :person OR pnd.person2 = :person'); $qb->setParameter('person', $person); $result = $qb->getQuery()->getResult(); $persons = []; + foreach ($result as $row) { if ($row->getPerson1() === $person) { $persons[] = $row->getPerson2(); diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php b/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php index ccc56b639..ffb02227e 100644 --- a/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/PersonRepository.php @@ -1,126 +1,74 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Repository; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; +use Exception; + +use function in_array; +use function str_replace; /** - * Class PersonRepository - * - * @package Chill\PersonBundle\Repository + * Class PersonRepository. */ class PersonRepository extends EntityRepository { /** - * @param string $phonenumber + * @param $centers + * + * @throws \Doctrine\ORM\NoResultException + * @throws \Doctrine\ORM\NonUniqueResultException + */ + public function countByPhone( + string $phonenumber, + $centers, + array $only = ['mobile', 'phone'] + ): int { + $qb = $this->createQueryBuilder('p'); + $qb->select('COUNT(p)'); + + $this->addByCenters($qb, $centers); + $this->addPhoneNumber($qb, $phonenumber, $only); + + return $qb->getQuery()->getSingleScalarResult(); + } + + /** * @param $centers * @param $firstResult * @param $maxResults - * @param array $only + * + * @throws Exception + * * @return mixed - * @throws \Exception */ public function findByPhone( - string $phonenumber, - $centers, + string $phonenumber, + $centers, $firstResult, $maxResults, array $only = ['mobile', 'phone'] ) { $qb = $this->createQueryBuilder('p'); $qb->select('p'); - + $this->addByCenters($qb, $centers); $this->addPhoneNumber($qb, $phonenumber, $only); - + $qb->setFirstResult($firstResult) - ->setMaxResults($maxResults) - ; - + ->setMaxResults($maxResults); + return $qb->getQuery()->getResult(); } - - /** - * @param string $phonenumber - * @param $centers - * @param array $only - * @return int - * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException - */ - public function countByPhone( - string $phonenumber, - $centers, - array $only = ['mobile', 'phone'] - ): int - { - $qb = $this->createQueryBuilder('p'); - $qb->select('COUNT(p)'); - - $this->addByCenters($qb, $centers); - $this->addPhoneNumber($qb, $phonenumber, $only); - - return $qb->getQuery()->getSingleScalarResult(); - } - - /** - * @param QueryBuilder $qb - * @param string $phonenumber - * @param array $only - * @throws \Exception - */ - protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only) - { - if (count($only) === 0) { - throw new \Exception("No array field to search"); - } - - $phonenumber = $this->parsePhoneNumber($phonenumber); - - $orX = $qb->expr()->orX(); - - if (\in_array('mobile', $only)) { - $orX->add($qb->expr()->like("REPLACE(p.mobilenumber, ' ', '')", ':phonenumber')); - } - if (\in_array('phone', $only)) { - $orX->add($qb->expr()->like("REPLACE(p.phonenumber, ' ', '')", ':phonenumber')); - } - - $qb->andWhere($orX); - - $qb->setParameter('phonenumber', '%'.$phonenumber.'%'); - } - - /** - * @param $phonenumber - * @return string - */ - protected function parsePhoneNumber($phonenumber): string - { - return \str_replace(' ', '', $phonenumber); - } - - /** - * @param QueryBuilder $qb - * @param array $centers - */ + protected function addByCenters(QueryBuilder $qb, array $centers) { if (count($centers) > 0) { @@ -128,4 +76,38 @@ class PersonRepository extends EntityRepository $qb->setParameter('centers', $centers); } } + + /** + * @throws Exception + */ + protected function addPhoneNumber(QueryBuilder $qb, string $phonenumber, array $only) + { + if (count($only) === 0) { + throw new Exception('No array field to search'); + } + + $phonenumber = $this->parsePhoneNumber($phonenumber); + + $orX = $qb->expr()->orX(); + + if (in_array('mobile', $only)) { + $orX->add($qb->expr()->like("REPLACE(p.mobilenumber, ' ', '')", ':phonenumber')); + } + + if (in_array('phone', $only)) { + $orX->add($qb->expr()->like("REPLACE(p.phonenumber, ' ', '')", ':phonenumber')); + } + + $qb->andWhere($orX); + + $qb->setParameter('phonenumber', '%' . $phonenumber . '%'); + } + + /** + * @param $phonenumber + */ + protected function parsePhoneNumber($phonenumber): string + { + return str_replace(' ', '', $phonenumber); + } } diff --git a/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php b/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php index b030e1617..67578dacb 100644 --- a/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/SocialWork/EvaluationRepository.php @@ -1,5 +1,12 @@ load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - } - - /** - * @return string - */ - public function getCacheDir() - { - return sys_get_temp_dir().'/PersonBundle/cache'; - } - - /** - * @return string - */ - public function getLogDir() - { - return sys_get_temp_dir().'/PersonBundle/logs'; + $loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml'); } } - diff --git a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/autoload.php b/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/autoload.php index 39dc0e2ba..a2dfe7f92 100644 --- a/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/autoload.php +++ b/src/Bundle/ChillPersonBundle/Resources/test/Fixtures/App/app/autoload.php @@ -1,11 +1,18 @@ loadClassCache(); diff --git a/src/Bundle/ChillPersonBundle/Search/PersonSearch.php b/src/Bundle/ChillPersonBundle/Search/PersonSearch.php index 34f79bb87..3add7bd52 100644 --- a/src/Bundle/ChillPersonBundle/Search/PersonSearch.php +++ b/src/Bundle/ChillPersonBundle/Search/PersonSearch.php @@ -1,80 +1,72 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Search; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Search\AbstractSearch; -use Doctrine\ORM\EntityManagerInterface; -use Chill\PersonBundle\Entity\Person; +use Chill\MainBundle\Search\HasAdvancedSearchFormInterface; +use Chill\MainBundle\Search\ParsingException; use Chill\MainBundle\Search\SearchInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use DateTime; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use Exception; +use LogicException; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; -use Chill\MainBundle\Search\ParsingException; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Role\Role; -use Chill\MainBundle\Pagination\PaginatorFactory; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Chill\MainBundle\Form\Type\ChillDateType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; -use Chill\MainBundle\Search\HasAdvancedSearchFormInterface; -use Doctrine\ORM\Query; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Role\Role; +use function array_merge; -class PersonSearch extends AbstractSearch implements ContainerAwareInterface, +class PersonSearch extends AbstractSearch implements + ContainerAwareInterface, HasAdvancedSearchFormInterface { use ContainerAwareTrait; + public const NAME = 'person_regular'; + + /** + * @var PaginatorFactory + */ + protected $paginatorFactory; + + private $_cacheQuery = []; + /** - * * @var EntityManagerInterface */ private $em; /** - * - * @var \Chill\MainBundle\Entity\User - */ - private $user; - - /** - * * @var AuthorizationHelper */ private $helper; /** - * - * @var PaginatorFactory + * @var \Chill\MainBundle\Entity\User */ - protected $paginatorFactory; - - const NAME = "person_regular"; - + private $user; public function __construct( - EntityManagerInterface $em, - TokenStorageInterface $tokenStorage, - AuthorizationHelper $helper, - PaginatorFactory $paginatorFactory) - { + EntityManagerInterface $em, + TokenStorageInterface $tokenStorage, + AuthorizationHelper $helper, + PaginatorFactory $paginatorFactory + ) { $this->em = $em; $this->user = $tokenStorage->getToken()->getUser(); $this->helper = $helper; @@ -82,11 +74,210 @@ class PersonSearch extends AbstractSearch implements ContainerAwareInterface, // throw an error if user is not a valid user if (!$this->user instanceof \Chill\MainBundle\Entity\User) { - throw new \LogicException('The user provided must be an instance' + throw new LogicException('The user provided must be an instance' . ' of Chill\MainBundle\Entity\User'); } } + public function buildForm(FormBuilderInterface $builder) + { + $builder + ->add('_default', TextType::class, [ + 'label' => 'First name or Last name', + 'required' => false, + ]) + ->add('firstname', TextType::class, [ + 'label' => 'First name', + 'required' => false, + ]) + ->add('lastname', TextType::class, [ + 'label' => 'Last name', + 'required' => false, + ]) + ->add('birthdate-after', ChillDateType::class, [ + 'label' => 'Birthdate after', + 'required' => false, + ]) + ->add('birthdate', ChillDateType::class, [ + 'label' => 'Birthdate', + 'required' => false, + ]) + ->add('birthdate-before', ChillDateType::class, [ + 'label' => 'Birthdate before', + 'required' => false, + ]) + ->add('gender', ChoiceType::class, [ + 'choices' => [ + 'Man' => Person::MALE_GENDER, + 'Woman' => Person::FEMALE_GENDER, + ], + 'label' => 'Gender', + 'required' => false, + ]); + } + + public function convertFormDataToQuery(array $data) + { + $string = '@person '; + + $string .= empty($data['_default']) ? '' : $data['_default'] . ' '; + + foreach (['firstname', 'lastname', 'gender'] as $key) { + $string .= empty($data[$key]) ? '' : $key . ':' . + // add quote if contains spaces + (strpos($data[$key], ' ') !== false ? '"' . $data[$key] . '"' : $data[$key]) + . ' '; + } + + foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) { + $string .= empty($data[$key]) ? + '' + : + $key . ':' . $data[$key]->format('Y-m-d') . ' '; + } + + return $string; + } + + public function convertTermsToFormData(array $terms) + { + foreach (['firstname', 'lastname', 'gender', '_default'] + as $key) { + $data[$key] = $terms[$key] ?? null; + } + + // parse dates + foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) { + if (\array_key_exists($key, $terms)) { + try { + $date = new DateTime($terms[$key]); + } catch (Exception $ex) { + throw new ParsingException("The date for {$key} is " + . 'not parsable', 0, $ex); + } + } + $data[$key] = $date ?? null; + } + + return $data; + } + + /** + * @return \Doctrine\ORM\QueryBuilder + */ + public function createQuery(array $terms) + { + //get from cache + $cacheKey = md5(serialize($terms)); + + if (array_key_exists($cacheKey, $this->_cacheQuery)) { + return clone $this->_cacheQuery[$cacheKey]; + } + + $qb = $this->em->createQueryBuilder(); + + $qb->from('ChillPersonBundle:Person', 'p'); + + if (array_key_exists('firstname', $terms)) { + $qb->andWhere($qb->expr()->like('UNACCENT(LOWER(p.firstName))', ':firstname')) + ->setParameter('firstname', '%' . $terms['firstname'] . '%'); + } + + if (array_key_exists('lastname', $terms)) { + $qb->andWhere($qb->expr()->like('UNACCENT(LOWER(p.lastName))', ':lastname')) + ->setParameter('lastname', '%' . $terms['lastname'] . '%'); + } + + foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) { + if (array_key_exists($key, $terms)) { + try { + $date = new DateTime($terms[$key]); + } catch (Exception $ex) { + throw new ParsingException('The date is ' + . 'not parsable', 0, $ex); + } + + switch ($key) { + case 'birthdate': + $qb->andWhere($qb->expr()->eq('p.birthdate', ':birthdate')) + ->setParameter('birthdate', $date); + + break; + + case 'birthdate-before': + $qb->andWhere($qb->expr()->lt('p.birthdate', ':birthdatebefore')) + ->setParameter('birthdatebefore', $date); + + break; + + case 'birthdate-after': + $qb->andWhere($qb->expr()->gt('p.birthdate', ':birthdateafter')) + ->setParameter('birthdateafter', $date); + + break; + + default: + throw new LogicException("this case {$key} should not exists"); + } + } + } + + if (array_key_exists('gender', $terms)) { + if (!in_array($terms['gender'], [Person::MALE_GENDER, Person::FEMALE_GENDER])) { + throw new ParsingException('The gender ' + . $terms['gender'] . ' is not accepted. Should be "' . Person::MALE_GENDER + . '" or "' . Person::FEMALE_GENDER . '"'); + } + + $qb->andWhere($qb->expr()->eq('p.gender', ':gender')) + ->setParameter('gender', $terms['gender']); + } + + if (array_key_exists('nationality', $terms)) { + try { + $country = $this->em->createQuery('SELECT c FROM ' + . 'ChillMainBundle:Country c WHERE ' + . 'LOWER(c.countryCode) LIKE :code') + ->setParameter('code', $terms['nationality']) + ->getSingleResult(); + } catch (\Doctrine\ORM\NoResultException $ex) { + throw new ParsingException('The country code "' . $terms['nationality'] . '" ' + . ', used in nationality, is unknow', 0, $ex); + } + + $qb->andWhere($qb->expr()->eq('p.nationality', ':nationality')) + ->setParameter('nationality', $country); + } + + if ('' !== $terms['_default']) { + $grams = explode(' ', $terms['_default']); + + foreach ($grams as $key => $gram) { + $qb->andWhere($qb->expr() + ->like('p.fullnameCanonical', 'UNACCENT(LOWER(:default_' . $key . '))')) + ->setParameter('default_' . $key, '%' . $gram . '%'); + } + } + + //restraint center for security + $reachableCenters = $this->helper->getReachableCenters( + $this->user, + new Role('CHILL_PERSON_SEE') + ); + $qb->andWhere($qb->expr() + ->in('p.center', ':centers')) + ->setParameter('centers', $reachableCenters); + + $this->_cacheQuery[$cacheKey] = $qb; + + return clone $qb; + } + + public function getAdvancedSearchTitle() + { + return 'Search within persons'; + } + /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::getOrder() @@ -105,64 +296,75 @@ class PersonSearch extends AbstractSearch implements ContainerAwareInterface, return true; } + /* + * (non-PHPdoc) + * @see \Chill\MainBundle\Search\SearchInterface::renderResult() + */ + public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html') + { + $total = $this->count($terms); + $paginator = $this->paginatorFactory->create($total); + + if ('html' === $format) { + return $this->container->get('templating')->render( + 'ChillPersonBundle:Person:list.html.twig', + [ + 'persons' => $this->search($terms, $start, $limit, $options), + 'pattern' => $this->recomposePattern($terms, ['nationality', + 'firstname', 'lastname', 'birthdate', 'gender', + 'birthdate-before', 'birthdate-after', ], $terms['_domain']), + 'total' => $total, + 'start' => $start, + 'search_name' => self::NAME, + 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], + 'paginator' => $paginator, + ] + ); + } + + if ('json' === $format) { + return [ + 'results' => $this->search($terms, $start, $limit, array_merge($options, ['simplify' => true])), + 'pagination' => [ + 'more' => $paginator->hasNextPage(), + ], + ]; + } + } + public function supports($domain, $format) { return 'person' === $domain; } - /* - * (non-PHPdoc) - * @see \Chill\MainBundle\Search\SearchInterface::renderResult() - */ - public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array(), $format = 'html') + protected function count(array $terms) { - $total = $this->count($terms); - $paginator = $this->paginatorFactory->create($total); + $qb = $this->createQuery($terms); - if ($format === 'html') { - return $this->container->get('templating')->render('ChillPersonBundle:Person:list.html.twig', - array( - 'persons' => $this->search($terms, $start, $limit, $options), - 'pattern' => $this->recomposePattern($terms, array('nationality', - 'firstname', 'lastname', 'birthdate', 'gender', - 'birthdate-before','birthdate-after'), $terms['_domain']), - 'total' => $total, - 'start' => $start, - 'search_name' => self::NAME, - 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], - 'paginator' => $paginator - )); - } elseif ($format === 'json') { - return [ - 'results' => $this->search($terms, $start, $limit, \array_merge($options, [ 'simplify' => true ])), - 'pagination' => [ - 'more' => $paginator->hasNextPage() - ] - ]; - } + $qb->select('COUNT(p.id)'); + + return $qb->getQuery()->getSingleScalarResult(); } /** - * - * @param string $pattern * @param int $start * @param int $limit - * @param array $options + * * @return Person[] */ - protected function search(array $terms, $start, $limit, array $options = array()) + protected function search(array $terms, $start, $limit, array $options = []) { $qb = $this->createQuery($terms, 'search'); - + if ($options['simplify'] ?? false) { $qb->select( - 'p.id', - $qb->expr()->concat( - 'p.firstName', - $qb->expr()->literal(' '), - 'p.lastName' - ).'AS text' - ); + 'p.id', + $qb->expr()->concat( + 'p.firstName', + $qb->expr()->literal(' '), + 'p.lastName' + ) . 'AS text' + ); } else { $qb->select('p'); } @@ -176,219 +378,11 @@ class PersonSearch extends AbstractSearch implements ContainerAwareInterface, $qb ->orderBy('p.firstName') ->addOrderBy('p.lastName'); - + if ($options['simplify'] ?? false) { return $qb->getQuery()->getResult(Query::HYDRATE_ARRAY); - } else { - return $qb->getQuery()->getResult(); } + + return $qb->getQuery()->getResult(); } - - protected function count(array $terms) - { - $qb = $this->createQuery($terms); - - $qb->select('COUNT(p.id)'); - - return $qb->getQuery()->getSingleScalarResult(); - } - - - private $_cacheQuery = array(); - - /** - * - * @param array $terms - * @return \Doctrine\ORM\QueryBuilder - */ - public function createQuery(array $terms) - { - //get from cache - $cacheKey = md5(serialize($terms)); - if (array_key_exists($cacheKey, $this->_cacheQuery)) { - return clone $this->_cacheQuery[$cacheKey]; - } - - $qb = $this->em->createQueryBuilder(); - - $qb->from('ChillPersonBundle:Person', 'p'); - - if (array_key_exists('firstname', $terms)) { - $qb->andWhere($qb->expr()->like('UNACCENT(LOWER(p.firstName))', ':firstname')) - ->setParameter('firstname', '%'.$terms['firstname'].'%'); - } - - if (array_key_exists('lastname', $terms)) { - $qb->andWhere($qb->expr()->like('UNACCENT(LOWER(p.lastName))', ':lastname')) - ->setParameter('lastname', '%'.$terms['lastname'].'%'); - } - - foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) - if (array_key_exists($key, $terms)) { - try { - $date = new \DateTime($terms[$key]); - } catch (\Exception $ex) { - throw new ParsingException('The date is ' - . 'not parsable', 0, $ex); - } - - switch($key) { - case 'birthdate': - $qb->andWhere($qb->expr()->eq('p.birthdate', ':birthdate')) - ->setParameter('birthdate', $date); - break; - case 'birthdate-before': - $qb->andWhere($qb->expr()->lt('p.birthdate', ':birthdatebefore')) - ->setParameter('birthdatebefore', $date); - break; - case 'birthdate-after': - $qb->andWhere($qb->expr()->gt('p.birthdate', ':birthdateafter')) - ->setParameter('birthdateafter', $date); - break; - default: - throw new \LogicException("this case $key should not exists"); - } - - } - - if (array_key_exists('gender', $terms)) { - if (!in_array($terms['gender'], array(Person::MALE_GENDER, Person::FEMALE_GENDER))) { - throw new ParsingException('The gender ' - .$terms['gender'].' is not accepted. Should be "'.Person::MALE_GENDER - .'" or "'.Person::FEMALE_GENDER.'"'); - } - - $qb->andWhere($qb->expr()->eq('p.gender', ':gender')) - ->setParameter('gender', $terms['gender']); - } - - if (array_key_exists('nationality', $terms)) { - try { - $country = $this->em->createQuery('SELECT c FROM ' - . 'ChillMainBundle:Country c WHERE ' - . 'LOWER(c.countryCode) LIKE :code') - ->setParameter('code', $terms['nationality']) - ->getSingleResult(); - } catch (\Doctrine\ORM\NoResultException $ex) { - throw new ParsingException('The country code "'.$terms['nationality'].'" ' - . ', used in nationality, is unknow', 0, $ex); - } - - $qb->andWhere($qb->expr()->eq('p.nationality', ':nationality')) - ->setParameter('nationality', $country); - } - - if ($terms['_default'] !== '') { - $grams = explode(' ', $terms['_default']); - - foreach($grams as $key => $gram) { - $qb->andWhere($qb->expr() - ->like('p.fullnameCanonical', 'UNACCENT(LOWER(:default_'.$key.'))')) - ->setParameter('default_'.$key, '%'.$gram.'%'); - } - } - - //restraint center for security - $reachableCenters = $this->helper->getReachableCenters($this->user, - new Role('CHILL_PERSON_SEE')); - $qb->andWhere($qb->expr() - ->in('p.center', ':centers')) - ->setParameter('centers', $reachableCenters) - ; - - $this->_cacheQuery[$cacheKey] = $qb; - - return clone $qb; - } - - public function buildForm(FormBuilderInterface $builder) - { - $builder - ->add('_default', TextType::class, [ - 'label' => 'First name or Last name', - 'required' => false - ]) - ->add('firstname', TextType::class, [ - 'label' => 'First name', - 'required' => false - ]) - ->add('lastname', TextType::class, [ - 'label' => 'Last name', - 'required' => false - ]) - ->add('birthdate-after', ChillDateType::class, [ - 'label' => 'Birthdate after', - 'required' => false - ]) - ->add('birthdate', ChillDateType::class, [ - 'label' => 'Birthdate', - 'required' => false - ]) - ->add('birthdate-before', ChillDateType::class, [ - 'label' => 'Birthdate before', - 'required' => false - ]) - ->add('gender', ChoiceType::class, [ - 'choices' => [ - 'Man' => Person::MALE_GENDER, - 'Woman' => Person::FEMALE_GENDER - ], - 'label' => 'Gender', - 'required' => false - ]) - ; - } - - public function convertFormDataToQuery(array $data) - { - $string = '@person '; - - $string .= empty($data['_default']) ? '' : $data['_default'].' '; - - foreach(['firstname', 'lastname', 'gender'] as $key) { - $string .= empty($data[$key]) ? '' : $key.':'. - // add quote if contains spaces - (strpos($data[$key], ' ') !== false ? '"'.$data[$key].'"': $data[$key]) - .' '; - } - - foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) { - $string .= empty($data[$key]) ? - '' - : - $key.':'.$data[$key]->format('Y-m-d').' ' - ; - } - - return $string; - } - - public function convertTermsToFormData(array $terms) - { - foreach(['firstname', 'lastname', 'gender', '_default'] - as $key) { - $data[$key] = $terms[$key] ?? null; - } - - // parse dates - foreach (['birthdate', 'birthdate-before', 'birthdate-after'] as $key) { - if (\array_key_exists($key, $terms)) { - try { - $date = new \DateTime($terms[$key]); - } catch (\Exception $ex) { - throw new ParsingException("The date for $key is " - . 'not parsable', 0, $ex); - } - } - $data[$key] = $date ?? null; - } - - return $data; - } - - public function getAdvancedSearchTitle() - { - return 'Search within persons'; - } - } diff --git a/src/Bundle/ChillPersonBundle/Search/PersonSearchByPhone.php b/src/Bundle/ChillPersonBundle/Search/PersonSearchByPhone.php index 08152144b..05bca0efd 100644 --- a/src/Bundle/ChillPersonBundle/Search/PersonSearchByPhone.php +++ b/src/Bundle/ChillPersonBundle/Search/PersonSearchByPhone.php @@ -1,95 +1,74 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Search; -use Chill\MainBundle\Search\AbstractSearch; -use Chill\PersonBundle\Repository\PersonRepository; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Search\SearchInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Pagination\PaginatorFactory; +use Chill\MainBundle\Search\AbstractSearch; +use Chill\MainBundle\Search\SearchInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Repository\PersonRepository; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Templating\EngineInterface; -/** - * - * - */ class PersonSearchByPhone extends AbstractSearch { - - /** - * - * @var PersonRepository - */ - private $personRepository; + public const NAME = 'phone'; /** - * - * @var TokenStorageInterface + * @var bool */ - private $tokenStorage; + protected $activeByDefault; + + /** + * @var Templating + */ + protected $engine; + + /** + * @var PaginatorFactory + */ + protected $paginatorFactory; /** - * * @var AuthorizationHelper */ private $helper; /** - * - * @var PaginatorFactory + * @var PersonRepository */ - protected $paginatorFactory; - + private $personRepository; + /** - * - * @var bool + * @var TokenStorageInterface */ - protected $activeByDefault; - - /** - * - * @var Templating - */ - protected $engine; - - const NAME = 'phone'; - + private $tokenStorage; + public function __construct( - PersonRepository $personRepository, - TokenStorageInterface $tokenStorage, - AuthorizationHelper $helper, + PersonRepository $personRepository, + TokenStorageInterface $tokenStorage, + AuthorizationHelper $helper, PaginatorFactory $paginatorFactory, EngineInterface $engine, - $activeByDefault) - { + $activeByDefault + ) { $this->personRepository = $personRepository; $this->tokenStorage = $tokenStorage; $this->helper = $helper; $this->paginatorFactory = $paginatorFactory; $this->engine = $engine; - $this->activeByDefault = $activeByDefault === 'always'; + $this->activeByDefault = 'always' === $activeByDefault; } - + public function getOrder(): int { return 110; @@ -100,34 +79,35 @@ class PersonSearchByPhone extends AbstractSearch return $this->activeByDefault; } - public function renderResult(array $terms, $start = 0, $limit = 50, $options = array(), $format = 'html') + public function renderResult(array $terms, $start = 0, $limit = 50, $options = [], $format = 'html') { $phonenumber = $terms['_default']; - $centers = $this->helper->getReachableCenters($this->tokenStorage + $centers = $this->helper->getReachableCenters($this->tokenStorage ->getToken()->getUser(), new Role(PersonVoter::SEE)); $total = $this->personRepository ->countByPhone($phonenumber, $centers); $persons = $this->personRepository - ->findByPhone($phonenumber, $centers, $start, $limit) - ; + ->findByPhone($phonenumber, $centers, $start, $limit); $paginator = $this->paginatorFactory ->create($total); - - return $this->engine->render('ChillPersonBundle:Person:list_by_phonenumber.html.twig', - array( - 'persons' => $persons, - 'pattern' => $this->recomposePattern($terms, array(), $terms['_domain'] ?? self::NAME), - 'phonenumber' => $phonenumber, - 'total' => $total, - 'start' => $start, - 'search_name' => self::NAME, - 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], - 'paginator' => $paginator - )); + + return $this->engine->render( + 'ChillPersonBundle:Person:list_by_phonenumber.html.twig', + [ + 'persons' => $persons, + 'pattern' => $this->recomposePattern($terms, [], $terms['_domain'] ?? self::NAME), + 'phonenumber' => $phonenumber, + 'total' => $total, + 'start' => $start, + 'search_name' => self::NAME, + 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], + 'paginator' => $paginator, + ] + ); } public function supports($domain, $format): bool { - return $domain === 'phone' && $format === 'html'; + return 'phone' === $domain && 'html' === $format; } } diff --git a/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php b/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php index 956f9a4d2..136e377f7 100644 --- a/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php +++ b/src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php @@ -1,60 +1,46 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\PersonBundle\Search; - -use Chill\PersonBundle\Entity\PersonNotDuplicate; -use Doctrine\ORM\EntityManagerInterface; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Role\Role; -use Chill\PersonBundle\Security\Authorization\PersonVoter; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\PersonBundle\Search; + +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Entity\PersonNotDuplicate; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Role\Role; + class SimilarPersonMatcher { - CONST SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL = 'alphabetical'; + public const SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL = 'alphabetical'; - CONST SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity'; + public const SIMILAR_SEARCH_ORDER_BY_SIMILARITY = 'similarity'; + + /** + * @var AuthorizationHelper + */ + protected $authorizationHelper; /** * @var EntityManagerInterface */ protected $em; - + /** - * @var AuthorizationHelper - */ - protected $authorizationHelper; - - /** - * @var TokenStorageInterface + * @var TokenStorageInterface */ protected $tokenStorage; - + public function __construct( - EntityManagerInterface $em, - AuthorizationHelper $authorizationHelper, + EntityManagerInterface $em, + AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage ) { $this->em = $em; @@ -74,8 +60,7 @@ class SimilarPersonMatcher . ' SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) >= :precision ' . ' ) ' . ' AND p.center IN (:centers)' - . ' AND p.id != :personId ' - ; + . ' AND p.id != :personId '; $notDuplicatePersons = $this->em->getRepository(PersonNotDuplicate::class) ->findNotDuplicatePerson($person); @@ -87,9 +72,11 @@ class SimilarPersonMatcher switch ($orderBy) { case self::SIMILAR_SEARCH_ORDER_BY_ALPHABETICAL: $dql .= ' ORDER BY p.fullnameCanonical ASC '; + break; + case self::SIMILAR_SEARCH_ORDER_BY_SIMILARITY: - default : + default: $dql .= ' ORDER BY SIMILARITY(p.fullnameCanonical, UNACCENT(LOWER(:fullName))) DESC '; } @@ -98,8 +85,7 @@ class SimilarPersonMatcher ->setParameter('fullName', $person->getFirstName() . ' ' . $person->getLastName()) ->setParameter('centers', $centers) ->setParameter('personId', $person->getId()) - ->setParameter('precision', $precision) - ; + ->setParameter('precision', $precision); if (count($notDuplicatePersons)) { $query->setParameter('notDuplicatePersons', $notDuplicatePersons); diff --git a/src/Bundle/ChillPersonBundle/Search/SimilarityPersonSearch.php b/src/Bundle/ChillPersonBundle/Search/SimilarityPersonSearch.php index ea2c9a5c7..aa24e33de 100644 --- a/src/Bundle/ChillPersonBundle/Search/SimilarityPersonSearch.php +++ b/src/Bundle/ChillPersonBundle/Search/SimilarityPersonSearch.php @@ -1,91 +1,85 @@ em = $em; $this->user = $tokenStorage->getToken()->getUser(); $this->helper = $helper; $this->paginatorFactory = $paginatorFactory; $this->personSearch = $personSearch; - + // throw an error if user is not a valid user if (!$this->user instanceof \Chill\MainBundle\Entity\User) { - throw new \LogicException('The user provided must be an instance' + throw new LogicException('The user provided must be an instance' . ' of Chill\MainBundle\Entity\User'); } } - + /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::getOrder() @@ -94,7 +88,7 @@ class SimilarityPersonSearch extends AbstractSearch { return 200; } - + /* * (non-PHPdoc) * @see \Chill\MainBundle\Search\SearchInterface::isActiveByDefault() @@ -103,72 +97,126 @@ class SimilarityPersonSearch extends AbstractSearch { return true; } - - public function supports($domain, $format) - { - return 'person' === $domain; - } - + /** - * @param array $terms * @param int $start * @param int $limit - * @param array $options * @param string $format + * * @return array */ - public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array(), $format = 'html') + public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html') { $total = $this->count($terms); $paginator = $this->paginatorFactory->create($total); - - if ($format === 'html') - { - if ($total !== 0) - { - return $this->container->get('templating')->render('ChillPersonBundle:Person:list.html.twig', - array( + + if ('html' === $format) { + if (0 !== $total) { + return $this->container->get('templating')->render( + 'ChillPersonBundle:Person:list.html.twig', + [ 'persons' => $this->search($terms, $start, $limit, $options), - 'pattern' => $this->recomposePattern($terms, array('nationality', + 'pattern' => $this->recomposePattern($terms, ['nationality', 'firstname', 'lastname', 'birthdate', 'gender', - 'birthdate-before','birthdate-after'), $terms['_domain']), + 'birthdate-before', 'birthdate-after', ], $terms['_domain']), 'total' => $total, 'start' => $start, 'search_name' => self::NAME, 'preview' => $options[SearchInterface::SEARCH_PREVIEW_OPTION], 'paginator' => $paginator, - 'title' => "Similar persons" - )); + 'title' => 'Similar persons', + ] + ); } - else { - return null; - } - - } elseif ($format === 'json') - { + + return null; + } + + if ('json' === $format) { return [ - 'results' => $this->search($terms, $start, $limit, \array_merge($options, [ 'simplify' => true ])), + 'results' => $this->search($terms, $start, $limit, array_merge($options, ['simplify' => true])), 'pagination' => [ - 'more' => $paginator->hasNextPage() - ] + 'more' => $paginator->hasNextPage(), + ], ]; } } - - + + public function supports($domain, $format) + { + return 'person' === $domain; + } + + protected function count(array $terms) + { + $qb = $this->createQuery($terms); + + $qb->select('COUNT(sp.id)'); + + return $qb->getQuery()->getSingleScalarResult(); + } + + /** + * @return \Doctrine\ORM\QueryBuilder + */ + protected function createQuery(array $terms) + { + //get from cache + $cacheKey = md5(serialize($terms)); + + if (array_key_exists($cacheKey, $this->_cacheQuery)) { + return clone $this->_cacheQuery[$cacheKey]; + } + + $qb = $this->em->createQueryBuilder(); + + $qb->select('sp') + ->from('ChillPersonBundle:Person', 'sp'); + + if ('' !== $terms['_default']) { + $grams = explode(' ', $terms['_default']); + + foreach ($grams as $key => $gram) { + $qb->andWhere('SIMILARITY(sp.fullnameCanonical, UNACCENT(LOWER(:default_' . $key . ')) ) >= 0.15') + ->setParameter('default_' . $key, '%' . $gram . '%'); + } + + $qb->andWhere( + $qb->expr() + ->notIn( + 'sp.id', + $this->personSearch + ->createQuery($terms) + ->addSelect('p.id') + ->getDQL() + ) + ); + } + + //restraint center for security + $reachableCenters = $this->helper->getReachableCenters( + $this->user, + new Role('CHILL_PERSON_SEE') + ); + $qb->andWhere($qb->expr() + ->in('sp.center', ':centers')) + ->setParameter('centers', $reachableCenters); + + $this->_cacheQuery[$cacheKey] = $qb; + + return clone $qb; + } + /** - * - * @param string $pattern * @param int $start * @param int $limit - * @param array $options + * * @return Person[] */ - protected function search(array $terms, $start, $limit, array $options = array()) + protected function search(array $terms, $start, $limit, array $options = []) { $qb = $this->createQuery($terms, 'search'); - - + if ($options['simplify'] ?? false) { $qb->select( 'sp.id', @@ -176,91 +224,26 @@ class SimilarityPersonSearch extends AbstractSearch 'sp.firstName', $qb->expr()->literal(' '), 'sp.lastName' - ).'AS text' + ) . 'AS text' ); } else { $qb->select('sp'); } - + $qb ->setMaxResults($limit) ->setFirstResult($start); - + //order by firstname, lastname - + $qb ->orderBy('sp.firstName') ->addOrderBy('sp.lastName'); - + if ($options['simplify'] ?? false) { return $qb->getQuery()->getResult(Query::HYDRATE_ARRAY); - } else { - return $qb->getQuery()->getResult(); } - } - - - protected function count(array $terms) - { - $qb = $this->createQuery($terms); - - $qb->select('COUNT(sp.id)'); - - return $qb->getQuery()->getSingleScalarResult(); + return $qb->getQuery()->getResult(); } - - - private $_cacheQuery = array(); - - /** - * - * @param array $terms - * @return \Doctrine\ORM\QueryBuilder - */ - protected function createQuery(array $terms) - { - //get from cache - $cacheKey = md5(serialize($terms)); - if (array_key_exists($cacheKey, $this->_cacheQuery)) { - return clone $this->_cacheQuery[$cacheKey]; - } - - $qb = $this->em->createQueryBuilder(); - - $qb ->select('sp') - ->from('ChillPersonBundle:Person', 'sp'); - - if ($terms['_default'] !== '') { - $grams = explode(' ', $terms['_default']); - - foreach($grams as $key => $gram) { - $qb->andWhere('SIMILARITY(sp.fullnameCanonical, UNACCENT(LOWER(:default_'.$key.')) ) >= 0.15') - ->setParameter('default_'.$key, '%'.$gram.'%'); - } - - $qb->andWhere($qb->expr() - ->notIn( - 'sp.id', - $this->personSearch - ->createQuery($terms) - ->addSelect('p.id') - ->getDQL() - ) - ); - } - - //restraint center for security - $reachableCenters = $this->helper->getReachableCenters($this->user, - new Role('CHILL_PERSON_SEE')); - $qb->andWhere($qb->expr() - ->in('sp.center', ':centers')) - ->setParameter('centers', $reachableCenters) - ; - - $this->_cacheQuery[$cacheKey] = $qb; - - return clone $qb; - } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php index ca92c6d7c..21a6aa945 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/AccompanyingPeriodVoter.php @@ -1,29 +1,46 @@ helper = $helper; + $this->helper = $helper; + } + + public function getRoles() + { + return $this->getAttributes(); + } + + public function getRolesWithHierarchy() + { + return ['Person' => $this->getRoles()]; + } + + public function getRolesWithoutScope() + { + return []; } protected function supports($attribute, $subject) @@ -51,23 +68,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRole private function getAttributes() { return [ - self::SEE + self::SEE, ]; } - - public function getRoles() - { - return $this->getAttributes(); - } - - public function getRolesWithoutScope() - { - return []; - } - - public function getRolesWithHierarchy() - { - return [ 'Person' => $this->getRoles() ]; - } - } diff --git a/src/Bundle/ChillPersonBundle/Security/Authorization/PersonVoter.php b/src/Bundle/ChillPersonBundle/Security/Authorization/PersonVoter.php index f81a6efa1..bce0f281f 100644 --- a/src/Bundle/ChillPersonBundle/Security/Authorization/PersonVoter.php +++ b/src/Bundle/ChillPersonBundle/Security/Authorization/PersonVoter.php @@ -1,109 +1,105 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Security\Authorization; -use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\Center; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ +use function in_array; + class PersonVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_PERSON_CREATE'; - const UPDATE = 'CHILL_PERSON_UPDATE'; - const SEE = 'CHILL_PERSON_SEE'; - const STATS = 'CHILL_PERSON_STATS'; - const LISTS = 'CHILL_PERSON_LISTS'; - const DUPLICATE = 'CHILL_PERSON_DUPLICATE'; - + public const CREATE = 'CHILL_PERSON_CREATE'; + + public const DUPLICATE = 'CHILL_PERSON_DUPLICATE'; + + public const LISTS = 'CHILL_PERSON_LISTS'; + + public const SEE = 'CHILL_PERSON_SEE'; + + public const STATS = 'CHILL_PERSON_STATS'; + + public const UPDATE = 'CHILL_PERSON_UPDATE'; + /** - * * @var AuthorizationHelper */ protected $helper; - + public function __construct(AuthorizationHelper $helper) { $this->helper = $helper; } - - protected function supports($attribute, $subject) - { - if ($subject instanceof Person) { - return \in_array($attribute, [ - self::CREATE, self::UPDATE, self::SEE, self::DUPLICATE - ]); - } elseif ($subject instanceof Center) { - return \in_array($attribute, [ - self::STATS, self::LISTS, self::DUPLICATE - ]); - } elseif ($subject === null) { - return $attribute === self::CREATE; - } else { - return false; - } - } - - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) - { - if (!$token->getUser() instanceof User) { - return false; - } - - if ($subject === null) { - $centers = $this->helper->getReachableCenters($token->getUser(), - new Role($attribute)); - - return count($centers) > 0; - } - - return $this->helper->userHasAccess($token->getUser(), $subject, $attribute); - } - - private function getAttributes() - { - return array(self::CREATE, self::UPDATE, self::SEE, self::STATS, self::LISTS, self::DUPLICATE); - } public function getRoles() { return $this->getAttributes(); } + public function getRolesWithHierarchy() + { + return ['Person' => $this->getRoles()]; + } + public function getRolesWithoutScope() { return $this->getAttributes(); } - - public function getRolesWithHierarchy() + + protected function supports($attribute, $subject) { - return [ 'Person' => $this->getRoles() ]; + if ($subject instanceof Person) { + return in_array($attribute, [ + self::CREATE, self::UPDATE, self::SEE, self::DUPLICATE, + ]); + } + + if ($subject instanceof Center) { + return in_array($attribute, [ + self::STATS, self::LISTS, self::DUPLICATE, + ]); + } + + if (null === $subject) { + return self::CREATE === $attribute; + } + + return false; } + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + if (!$token->getUser() instanceof User) { + return false; + } + + if (null === $subject) { + $centers = $this->helper->getReachableCenters( + $token->getUser(), + new Role($attribute) + ); + + return count($centers) > 0; + } + + return $this->helper->userHasAccess($token->getUser(), $subject, $attribute); + } + + private function getAttributes() + { + return [self::CREATE, self::UPDATE, self::SEE, self::STATS, self::LISTS, self::DUPLICATE]; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodNormalizer.php index e953b5c49..209d4418b 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodNormalizer.php @@ -1,34 +1,23 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Serializer\Normalizer; use Chill\PersonBundle\Entity\AccompanyingPeriod; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - - -class AccompanyingPeriodNormalizer implements NormalizerInterface, NormalizerAwareInterface { +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +class AccompanyingPeriodNormalizer implements NormalizerInterface, NormalizerAwareInterface +{ protected ?NormalizerInterface $normalizer = null; - public function normalize($period, string $format = null, array $context = array()) + public function normalize($period, ?string $format = null, array $context = []) { /** @var AccompanyingPeriod $period */ return [ @@ -43,17 +32,17 @@ class AccompanyingPeriodNormalizer implements NormalizerInterface, NormalizerAwa 'origin' => $this->normalizer->normalize($period->getOrigin(), $format), 'intensity' => $period->getIntensity(), 'emergency' => $period->isEmergency(), - 'confidential' => $period->isConfidential() + 'confidential' => $period->isConfidential(), ]; } - public function supportsNormalization($data, string $format = null): bool - { - return $data instanceof AccompanyingPeriod; - } - public function setNormalizer(NormalizerInterface $normalizer) { $this->normalizer = $normalizer; } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof AccompanyingPeriod; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php index 59e430827..a1d0d5a67 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/AccompanyingPeriodParticipationNormalizer.php @@ -1,51 +1,40 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Serializer\Normalizer; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; -use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; - - -class AccompanyingPeriodParticipationNormalizer implements NormalizerInterface, NormalizerAwareInterface { +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +class AccompanyingPeriodParticipationNormalizer implements NormalizerInterface, NormalizerAwareInterface +{ protected ?NormalizerInterface $normalizer = null; - public function normalize($participation, string $format = null, array $context = array()) + public function normalize($participation, ?string $format = null, array $context = []) { /** @var AccompanyingPeriodParticipation $participation */ return [ 'id' => $participation->getId(), 'startDate' => $this->normalizer->normalize($participation->getStartDate(), $format), 'endDate' => $this->normalizer->normalize($participation->getEndDate(), $format), - 'person' => $this->normalizer->normalize($participation->getPerson(), $format) + 'person' => $this->normalizer->normalize($participation->getPerson(), $format), ]; } - public function supportsNormalization($data, string $format = null): bool - { - return $data instanceof AccompanyingPeriodParticipation; - } - public function setNormalizer(NormalizerInterface $normalizer) { $this->normalizer = $normalizer; } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof AccompanyingPeriodParticipation; + } } diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php index d88d27ddc..e9a43806b 100644 --- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php +++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonNormalizer.php @@ -1,54 +1,61 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Serializer\Normalizer; use Chill\PersonBundle\Entity\Person; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; -use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; use Chill\PersonBundle\Repository\PersonRepository; use Symfony\Component\Serializer\Exception\RuntimeException; use Symfony\Component\Serializer\Exception\UnexpectedValueException; - +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface; +use Symfony\Component\Serializer\Normalizer\NormalizerInterface; /** - * Serialize a Person entity - * + * Serialize a Person entity. */ class PersonNormalizer implements NormalizerInterface, NormalizerAwareInterface, DenormalizerInterface { + public const GET_PERSON = 'get_person'; protected NormalizerInterface $normalizer; protected PersonRepository $repository; - public const GET_PERSON = 'get_person'; - public function __construct(PersonRepository $repository) { $this->repository = $repository; } - public function normalize($person, string $format = null, array $context = array()) + public function denormalize($data, string $type, ?string $format = null, array $context = []): Person + { + if ($context[self::GET_PERSON] ?? true) { + $id = $data['id'] ?? null; + + if (null === $id) { + throw new RuntimeException('missing id into person object'); + } + } + /** var Person $person */ + $person = $this->repository->findOneById($id); + + if (null === $person) { + return UnexpectedValueException('person id not found'); + } + + return $person; + } + + public function normalize($person, ?string $format = null, array $context = []) { /** @var Person $person */ return [ @@ -56,40 +63,22 @@ class PersonNormalizer implements 'firstName' => $person->getFirstName(), 'lastName' => $person->getLastName(), 'birthdate' => $this->normalizer->normalize($person->getBirthdate()), - 'center' => $this->normalizer->normalize($person->getCenter()) + 'center' => $this->normalizer->normalize($person->getCenter()), ]; } - public function denormalize($data, string $type, string $format = null, array $context = []): Person - { - if ($context[self::GET_PERSON] ?? true) { - $id = $data['id'] ?? null; - if (NULL === $id) { - throw new RuntimeException("missing id into person object"); - } - } - /** var Person $person */ - $person = $this->repository->findOneById($id); - - if (NULL === $person) { - return UnexpectedValueException("person id not found"); - } - - return $person; - } - - public function supportsNormalization($data, string $format = null): bool - { - return $data instanceof Person; - } - - public function supportsDenormalization($data, string $type, ?string $format = NULL): bool - { - return Person::class === $type; - } - public function setNormalizer(NormalizerInterface $normalizer) { $this->normalizer = $normalizer; } + + public function supportsDenormalization($data, string $type, ?string $format = null): bool + { + return Person::class === $type; + } + + public function supportsNormalization($data, ?string $format = null): bool + { + return $data instanceof Person; + } } diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/ClosingMotiveRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/ClosingMotiveRender.php index 8b54fca02..158de15f8 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/ClosingMotiveRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/ClosingMotiveRender.php @@ -1,75 +1,80 @@ '; - + private const SEPARATOR = ' > '; + /** - * * @var TranslatableStringHelper */ private $translatableStringHelper; - + public function __construct(TranslatableStringHelper $translatableStringHelper) { $this->translatableStringHelper = $translatableStringHelper; } - + public function renderBox($entity, array $options): string { - return - $this->getDefaultOpeningBox('closing-motive'). - $this->renderString($entity, $options). - $this->getDefaultClosingBox() - ; + return + $this->getDefaultOpeningBox('closing-motive') . + $this->renderString($entity, $options) . + $this->getDefaultClosingBox(); } /** - * * @param ClosingMotive $entity - * @param array $options - * @return string */ public function renderString($entity, array $options): string { - return $this->renderStringRecursive($entity, - '', //$this->translatableStringHelper->localize($entity->getName()), - $options); - } - - protected function renderStringRecursive(ClosingMotive $motive, $existing, array $options) - { - $newExisting = $this->translatableStringHelper->localize($motive->getName()); - - if ($motive->hasParent()) { - - if (!empty($existing)) { - $newExisting = $newExisting.self::SEPARATOR.$existing; - } - - return $this->renderStringRecursive($motive->getParent(), $newExisting, - $options); - } else { - if (!empty($existing)) { - return $newExisting.self::SEPARATOR.$existing; - } else { - return $newExisting; - } - } + return $this->renderStringRecursive( + $entity, + '', //$this->translatableStringHelper->localize($entity->getName()), + $options + ); } public function supports($entity, array $options): bool { return $entity instanceof ClosingMotive; } + + protected function renderStringRecursive(ClosingMotive $motive, $existing, array $options) + { + $newExisting = $this->translatableStringHelper->localize($motive->getName()); + + if ($motive->hasParent()) { + if (!empty($existing)) { + $newExisting = $newExisting . self::SEPARATOR . $existing; + } + + return $this->renderStringRecursive( + $motive->getParent(), + $newExisting, + $options + ); + } + + if (!empty($existing)) { + return $newExisting . self::SEPARATOR . $existing; + } + + return $newExisting; + } } diff --git a/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php b/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php index d1f554492..326b17726 100644 --- a/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php +++ b/src/Bundle/ChillPersonBundle/Templating/Entity/PersonRender.php @@ -1,113 +1,96 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Templating\Entity; use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; -use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Config\ConfigPersonAltNamesHelper; +use Chill\PersonBundle\Entity\Person; + +use function array_key_exists; /** - * Render a Person - * + * Render a Person. */ class PersonRender extends AbstractChillEntityRender { /** - * * @var ConfigPersonAltNamesHelper */ protected $configAltNamesHelper; - + public function __construct(ConfigPersonAltNamesHelper $configAltNamesHelper) { $this->configAltNamesHelper = $configAltNamesHelper; } - + /** - * * @param Person $person - * @param array $options - * @return string */ public function renderBox($person, array $options): string { - return - $this->getDefaultOpeningBox('person'). - ''.$person->getFirstName().''. - ' '.$person->getLastName().''. - $this->addAltNames($person, true). - $this->getDefaultClosingBox() - ; + return + $this->getDefaultOpeningBox('person') . + '' . $person->getFirstName() . '' . + ' ' . $person->getLastName() . '' . + $this->addAltNames($person, true) . + $this->getDefaultClosingBox(); } /** - * * @param Person $person - * @param array $options - * @return string */ public function renderString($person, array $options): string { - return $person->getFirstName().' '.$person->getLastName() - .$this->addAltNames($person, false); - } - - protected function addAltNames(Person $person, bool $addSpan) - { - $str = ''; - - if ($this->configAltNamesHelper->hasAltNames()) { - $altNames = $this->configAltNamesHelper->getChoices(); - $isFirst = true; - - foreach ($person->getAltNames()->getIterator() as $altName) { - /** @var \Chill\PersonBundle\Entity\PersonAltName $altName */ - if (\array_key_exists($altName->getKey(), $altNames)) { - if ($isFirst) { - $str .= " ("; - $isFirst = false; - } else { - $str.= " "; - } - if ($addSpan) { - $str .= ''; - } - $str .= $altName->getLabel(); - - if ($addSpan) { - $str .= ""; - } - } - } - - if (!$isFirst) { - $str .= ")"; - } - } - - return $str; + return $person->getFirstName() . ' ' . $person->getLastName() + . $this->addAltNames($person, false); } public function supports($entity, array $options): bool { return $entity instanceof Person; } + + protected function addAltNames(Person $person, bool $addSpan) + { + $str = ''; + + if ($this->configAltNamesHelper->hasAltNames()) { + $altNames = $this->configAltNamesHelper->getChoices(); + $isFirst = true; + + foreach ($person->getAltNames()->getIterator() as $altName) { + /** @var \Chill\PersonBundle\Entity\PersonAltName $altName */ + if (array_key_exists($altName->getKey(), $altNames)) { + if ($isFirst) { + $str .= ' ('; + $isFirst = false; + } else { + $str .= ' '; + } + + if ($addSpan) { + $str .= ''; + } + $str .= $altName->getLabel(); + + if ($addSpan) { + $str .= ''; + } + } + } + + if (!$isFirst) { + $str .= ')'; + } + } + + return $str; + } } diff --git a/src/Bundle/ChillPersonBundle/Test/PreparePersonTrait.php b/src/Bundle/ChillPersonBundle/Test/PreparePersonTrait.php index e8e495a04..e6fe2efe3 100644 --- a/src/Bundle/ChillPersonBundle/Test/PreparePersonTrait.php +++ b/src/Bundle/ChillPersonBundle/Test/PreparePersonTrait.php @@ -1,56 +1,37 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Test; -use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\Center; +use Chill\PersonBundle\Entity\Person; -/** - * - * - * @author Julien Fastré - */ trait PreparePersonTrait { - /** - * prepare a person - * - * Properties added are : + * prepare a person. + * + * Properties added are : * - firstname * - lastname * - gender - * + * * This person should not be persisted in a database - * - * @param Center $center + * * @return Person */ protected function preparePerson(Center $center) { return (new Person()) - ->setCenter($center) - ->setFirstName('test firstname') - ->setLastName('default lastname') - ->setGender(Person::MALE_GENDER) - ; + ->setCenter($center) + ->setFirstName('test firstname') + ->setLastName('default lastname') + ->setGender(Person::MALE_GENDER); } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php index 61b5307a4..c89fc114d 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php @@ -1,149 +1,56 @@ , * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; - -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Chill\MainBundle\Entity\Center; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Center; -use Doctrine\Common\Collections\Criteria; use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\Request; +use function array_map; +use function array_pop; +use function array_rand; +use function json_decode; +use function json_encode; +use function strlen; +use function substr; /** - * Test api for AccompanyingCourseControllerTest + * Test api for AccompanyingCourseControllerTest. + * + * @internal + * @coversNothing */ class AccompanyingCourseApiControllerTest extends WebTestCase { protected static EntityManagerInterface $em; /** - * Setup before the first test of this class (see phpunit doc) + * Setup before the first test of this class (see phpunit doc). */ public static function setUpBeforeClass() { static::bootKernel(); } - + /** - * Setup before each test method (see phpunit doc) + * Setup before each test method (see phpunit doc). */ public function setUp() { - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); - } - - /** - * - * @dataProvider dataGenerateRandomAccompanyingCourse - */ - public function testAccompanyingCourseShow(int $personId, AccompanyingPeriod $period) - { - $c = $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId())); - $response = $this->client->getResponse(); - - $this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)"); - - $data = \json_decode($response->getContent()); - $this->assertEquals($data->id, $period->getId(), - "test that the response's data contains the id of the period" - ); - $this->assertGreaterThan(0, $data->participations); - } - - public function testShow404() - { - $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', 99999)); - $response = $this->client->getResponse(); - - $this->assertEquals(404, $response->getStatusCode(), "Test that the response of rest api has a status code 'not found' (404)"); - } - - /** - * - * @dataProvider dataGenerateRandomAccompanyingCourse - */ - public function testAccompanyingCourseAddParticipation(int $personId, AccompanyingPeriod $period) - { - $this->client->request( - Request::METHOD_POST, - sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'id' => $personId ]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)"); - $this->assertArrayHasKey('id', $data); - $this->assertArrayHasKey('startDate', $data); - $this->assertNotNull($data['startDate']); - - // check by deownloading the accompanying cours - - $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId())); - - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent()); - - // check that the person id is contained - $participationsPersonsIds = \array_map( - function($participation) { return $participation->person->id; }, - $data->participations); - - $this->assertContains($personId, $participationsPersonsIds); - - // check removing the participation - $this->client->request( - Request::METHOD_DELETE, - sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()), - [], // parameters - [], // files - [], // server parameters - \json_encode([ 'id' => $personId ]) - ); - $response = $this->client->getResponse(); - $data = \json_decode($response->getContent(), true); - - $this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)"); - $this->assertArrayHasKey('id', $data); - $this->assertArrayHasKey('startDate', $data); - $this->assertNotNull($data['startDate']); - $this->assertArrayHasKey('endDate', $data); - $this->assertNotNull($data['endDate']); - - - // set to variable for tear down - $this->personId = $personId; - $this->period = $period; + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ]); } protected function tearDown() @@ -153,7 +60,7 @@ class AccompanyingCourseApiControllerTest extends WebTestCase $testAddParticipationName = 'testAccompanyingCourseAddParticipation'; - if ($testAddParticipationName !== \substr($this->getName(), 0, \strlen($testAddParticipationName))) { + if (substr($this->getName(), 0, strlen($testAddParticipationName)) !== $testAddParticipationName) { return; } @@ -161,10 +68,9 @@ class AccompanyingCourseApiControllerTest extends WebTestCase $participation = $em ->getRepository(AccompanyingPeriodParticipation::class) - ->findOneBy(['person' => $this->personId, 'accompanyingPeriod' => $this->period]) - ; + ->findOneBy(['person' => $this->personId, 'accompanyingPeriod' => $this->period]); - if (NULL !== $participation) { + if (null !== $participation) { $em->remove($participation); $em->flush(); } @@ -173,9 +79,9 @@ class AccompanyingCourseApiControllerTest extends WebTestCase public function dataGenerateRandomAccompanyingCourse() { // note about max result for person query, and maxGenerated: - // + // // in the final loop, an id is popped out of the personIds array twice: - // + // // * one for getting the person, which will in turn provide his accompanying period; // * one for getting the personId to populate to the data manager // @@ -186,29 +92,117 @@ class AccompanyingCourseApiControllerTest extends WebTestCase static::bootKernel(); $em = static::$container->get(EntityManagerInterface::class); $center = $em->getRepository(Center::class) - ->findOneBy(array('name' => 'Center A')); + ->findOneBy(['name' => 'Center A']); - $personIds = $em->createQuery("SELECT p.id FROM ". - Person::class." p ". - " WHERE p.center = :center") + $personIds = $em->createQuery('SELECT p.id FROM ' . + Person::class . ' p ' . + ' WHERE p.center = :center') ->setParameter('center', $center) ->setMaxResults($maxResults) ->getScalarResult(); - + // create a random order shuffle($personIds); $nbGenerated = 0; + while ($nbGenerated < $maxGenerated) { - $id = \array_pop($personIds)["id"]; + $id = array_pop($personIds)['id']; $person = $em->getRepository(Person::class) ->find($id); $periods = $person->getAccompanyingPeriods(); - yield [\array_pop($personIds)["id"], $periods[\array_rand($periods)] ]; + yield [array_pop($personIds)['id'], $periods[array_rand($periods)]]; - $nbGenerated++; + ++$nbGenerated; } } + + /** + * @dataProvider dataGenerateRandomAccompanyingCourse + */ + public function testAccompanyingCourseAddParticipation(int $personId, AccompanyingPeriod $period) + { + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()), + [], // parameters + [], // files + [], // server parameters + json_encode(['id' => $personId]) + ); + $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); + + $this->assertEquals(200, $response->getStatusCode(), 'Test that the response of rest api has a status code ok (200)'); + $this->assertArrayHasKey('id', $data); + $this->assertArrayHasKey('startDate', $data); + $this->assertNotNull($data['startDate']); + + // check by deownloading the accompanying cours + + $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId())); + + $response = $this->client->getResponse(); + $data = json_decode($response->getContent()); + + // check that the person id is contained + $participationsPersonsIds = array_map( + function ($participation) { return $participation->person->id; }, + $data->participations + ); + + $this->assertContains($personId, $participationsPersonsIds); + + // check removing the participation + $this->client->request( + Request::METHOD_DELETE, + sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()), + [], // parameters + [], // files + [], // server parameters + json_encode(['id' => $personId]) + ); + $response = $this->client->getResponse(); + $data = json_decode($response->getContent(), true); + + $this->assertEquals(200, $response->getStatusCode(), 'Test that the response of rest api has a status code ok (200)'); + $this->assertArrayHasKey('id', $data); + $this->assertArrayHasKey('startDate', $data); + $this->assertNotNull($data['startDate']); + $this->assertArrayHasKey('endDate', $data); + $this->assertNotNull($data['endDate']); + + // set to variable for tear down + $this->personId = $personId; + $this->period = $period; + } + + /** + * @dataProvider dataGenerateRandomAccompanyingCourse + */ + public function testAccompanyingCourseShow(int $personId, AccompanyingPeriod $period) + { + $c = $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId())); + $response = $this->client->getResponse(); + + $this->assertEquals(200, $response->getStatusCode(), 'Test that the response of rest api has a status code ok (200)'); + + $data = json_decode($response->getContent()); + $this->assertEquals( + $data->id, + $period->getId(), + "test that the response's data contains the id of the period" + ); + $this->assertGreaterThan(0, $data->participations); + } + + public function testShow404() + { + $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', 99999)); + $response = $this->client->getResponse(); + + $this->assertEquals(404, $response->getStatusCode(), "Test that the response of rest api has a status code 'not found' (404)"); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php index 40f4936b4..8b629f58c 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingPeriodControllerTest.php @@ -1,78 +1,77 @@ , * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; - -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; +use DateTime; use Doctrine\Common\Collections\Criteria; +use LogicalException; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the creation or deletion of accompanying periods - * - * The person on which the test is done has a (current) period opened (and not + * Test the creation or deletion of accompanying periods. + * + * The person on which the test is done has a (current) period opened (and not * closed) starting the 2015-01-05. + * + * @internal + * @coversNothing */ class AccompanyingPeriodControllerTest extends WebTestCase { - /** @var \Symfony\Component\BrowserKit\Client */ - protected $client; - - /** @var Person The person on which the form is applied*/ - protected $person; - - /** @var \Doctrine\ORM\EntityManagerInterface */ - protected static $em; - - const OPENING_INPUT = 'chill_personbundle_accompanyingperiod[openingDate]'; - const CLOSING_INPUT = 'chill_personbundle_accompanyingperiod[closingDate]'; - const CLOSING_MOTIVE_INPUT = 'chill_personbundle_accompanyingperiod[closingMotive]'; - + public const CLOSING_INPUT = 'chill_personbundle_accompanyingperiod[closingDate]'; + + public const CLOSING_MOTIVE_INPUT = 'chill_personbundle_accompanyingperiod[closingMotive]'; + + public const OPENING_INPUT = 'chill_personbundle_accompanyingperiod[openingDate]'; + /** - * Setup before the first test of this class (see phpunit doc) + * @var \Symfony\Component\BrowserKit\Client + */ + protected $client; + + /** + * @var \Doctrine\ORM\EntityManagerInterface + */ + protected static $em; + + /** + * @var Person The person on which the form is applied + */ + protected $person; + + /** + * Setup before the first test of this class (see phpunit doc). */ public static function setUpBeforeClass() { static::bootKernel(); static::$em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); + ->get('doctrine.orm.entity_manager'); } - + /** - * Setup before each test method (see phpunit doc) + * Setup before each test method (see phpunit doc). */ public function setUp() { - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); - + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ]); + $center = static::$em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - - $this->person = (new Person(new \DateTime('2015-01-05'))) + ->findOneBy(['name' => 'Center A']); + + $this->person = (new Person(new DateTime('2015-01-05'))) ->setFirstName('Roland') ->setLastName('Gallorime') ->setCenter($center) @@ -81,139 +80,21 @@ class AccompanyingPeriodControllerTest extends WebTestCase static::$em->persist($this->person); static::$em->flush(); } - - /** - * TearDown after each test method (see phpunit doc) + + /** + * TearDown after each test method (see phpunit doc). */ public function tearDown() { - static::$em->refresh($this->person); - static::$em->remove($this->person); - - static::$em->flush(); - } - - /** - * Given an array of periods (key openingDate, closingDate (optioal), - * closingMotive) generate the periods in the db. - */ - protected function generatePeriods(array $periods) - { - foreach ($periods as $periodDef) { - $period = new AccompanyingPeriod(new \DateTime($periodDef['openingDate'])); - - if (array_key_exists('closingDate', $periodDef)) { - if (!array_key_exists('closingMotive', $periodDef)) { - throw new \LogicalException('you must define a closing ' - . 'motive into your periods fixtures'); - } - - $period->setClosingDate(new \DateTime($periodDef['closingDate'])) - ->setClosingMotive($periodDef['closingMotive']); - } - - $this->person->addAccompanyingPeriod($period); - static::$em->persist($period); - } - + static::$em->refresh($this->person); + static::$em->remove($this->person); + static::$em->flush(); } - - /** - * Get the last value of a closing motive - * @var \Symfony\Component\DomCrawler\Form The form - * @return Chill\PersonBundle\Entity\AccompanyingPeriod The last value of closing - * motive - */ - protected function getLastValueOnClosingMotive(\Symfony\Component\DomCrawler\Form $form) - { - $values = $form->get(self::CLOSING_MOTIVE_INPUT) - ->availableOptionValues(); - return end($values); - } - - /** - * Get a random closing motive - * @return Chill\PersonBundle\Entity\AccompanyingPeriod The last closing motive - */ - protected function getRandomClosingMotive() - { - $motives = static::$em - ->getRepository('ChillPersonBundle:AccompanyingPeriod\ClosingMotive') - ->findAll(); - return end($motives); - } - - /** - * Test the closing of a periods - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and we fill the close form (at /en/person/[id]/accompanying-period/close - * with : dateClosing: 2015-02-01 - * with : the last closing motive in list - * Then the response should redirect to period view - * And the next page should have a `.error` element present in page - * - * @todo - */ - public function testClosingCurrentPeriod() - { - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/close'); - - $form = $crawler->selectButton('Close accompanying period')->form(); - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue((new \DateTime('2015-02-01'))->format('d-m-Y')); - - $cr = $this->client->submit($form); - - $this->assertTrue($this->client->getResponse()->isRedirect( - '/en/person/'.$this->person->getId().'/accompanying-period'), - 'the server redirects to /accompanying-period page'); - $this->assertGreaterThan(0, $this->client->followRedirect() - ->filter('.success')->count(), - "a 'success' element is shown"); - } - /** - * Test the closing of a periods - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and we fill the close form (at /en/person/[id]/accompanying-period/close - * with : dateClosing: 2014-01-01 - * with : the last closing motive in list - * Then the response should redirect to period view - * And the next page should have a `.error` element present in page - * - * @todo - */ - public function testClosingCurrentPeriodWithDateClosingBeforeOpeningFails() - { - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/close'); - - $form = $crawler->selectButton('Close accompanying period')->form(); - - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue((new \DateTime('2014-01-01'))->format('d-m-Y')); - - $crawlerResponse = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stays on the /close page'); - $this->assertGreaterThan(0, $crawlerResponse - ->filter('.error')->count(), - "an '.error' element is shown"); - } - - /** - * Test the creation of a new period - * + * Test the creation of a new period. + * * Given that a person as an accompanying period opened since 2015-01-05 * and we create a new period * with : dateClosing: 2014-12-31 @@ -224,29 +105,160 @@ class AccompanyingPeriodControllerTest extends WebTestCase public function testAddNewPeriodBeforeActual() { $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton('Create an accompanying period')->form(); $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); + ->setValue($this->getLastValueOnClosingMotive($form)); $form->get(self::CLOSING_INPUT) - ->setValue('31-12-2014'); + ->setValue('31-12-2014'); $form->get(self::OPENING_INPUT) - ->setValue('01-01-2014'); - + ->setValue('01-01-2014'); + $this->client->submit($form); - - $this->assertTrue($this->client->getResponse()->isRedirect( - '/en/person/'.$this->person->getId().'/accompanying-period'), - 'the server redirects to /accompanying-period page'); - $this->assertGreaterThan(0, $this->client->followRedirect() - ->filter('.success')->count(), - "a 'success' element is shown"); + + $this->assertTrue( + $this->client->getResponse()->isRedirect( + '/en/person/' . $this->person->getId() . '/accompanying-period' + ), + 'the server redirects to /accompanying-period page' + ); + $this->assertGreaterThan( + 0, + $this->client->followRedirect() + ->filter('.success')->count(), + "a 'success' element is shown" + ); } - + /** - * Create a period with closing after current fails - * + * Test the closing of a periods. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and we fill the close form (at /en/person/[id]/accompanying-period/close + * with : dateClosing: 2015-02-01 + * with : the last closing motive in list + * Then the response should redirect to period view + * And the next page should have a `.error` element present in page + * + * @todo + */ + public function testClosingCurrentPeriod() + { + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/close'); + + $form = $crawler->selectButton('Close accompanying period')->form(); + + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue((new DateTime('2015-02-01'))->format('d-m-Y')); + + $cr = $this->client->submit($form); + + $this->assertTrue( + $this->client->getResponse()->isRedirect( + '/en/person/' . $this->person->getId() . '/accompanying-period' + ), + 'the server redirects to /accompanying-period page' + ); + $this->assertGreaterThan( + 0, + $this->client->followRedirect() + ->filter('.success')->count(), + "a 'success' element is shown" + ); + } + + /** + * Test the closing of a periods. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and we fill the close form (at /en/person/[id]/accompanying-period/close + * with : dateClosing: 2014-01-01 + * with : the last closing motive in list + * Then the response should redirect to period view + * And the next page should have a `.error` element present in page + * + * @todo + */ + public function testClosingCurrentPeriodWithDateClosingBeforeOpeningFails() + { + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/close'); + + $form = $crawler->selectButton('Close accompanying period')->form(); + + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue((new DateTime('2014-01-01'))->format('d-m-Y')); + + $crawlerResponse = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stays on the /close page' + ); + $this->assertGreaterThan( + 0, + $crawlerResponse + ->filter('.error')->count(), + "an '.error' element is shown" + ); + } + + /** + * create a period with date closing and date opening inside another period + * fails. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 + * and we create a new period + * with : dateClosing: 2014-02-01 + * with : dateOpening: 2014-03-01 + * with : the last closing motive in list + * Then the response should not redirect + * and a error element is shown on the response page + */ + public function testCreatePeriodAfterOpeningFails() + { + $this->generatePeriods([ + [ + 'openingDate' => '2014-01-01', + 'closingDate' => '2014-12-31', + 'closingMotive' => $this->getRandomClosingMotive(), + ], + ]); + + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Create an accompanying period')->form(); + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue('2014-02-01'); + $form->get(self::OPENING_INPUT) + ->setValue('01-03-2014'); + + $crawlerResponse = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawlerResponse->filter('.error')->count(), + "an 'error' element is shown" + ); + } + + /** + * Create a period with closing after current fails. + * * Given that a person as an accompanying period opened since 2015-01-05 * and we create a new period * with : dateClosing: 2015-02-01 (after 2015-01-05) @@ -258,27 +270,160 @@ class AccompanyingPeriodControllerTest extends WebTestCase public function testCreatePeriodWithClosingAfterCurrentFails() { $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton('Create an accompanying period')->form(); $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); + ->setValue($this->getLastValueOnClosingMotive($form)); $form->get(self::CLOSING_INPUT) - ->setValue('01-02-2015'); + ->setValue('01-02-2015'); $form->get(self::OPENING_INPUT) - ->setValue('31-12-2014'); - + ->setValue('31-12-2014'); + $crawler = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawler->filter('.error')->count(), - "an 'error' element is shown"); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.error')->count(), + "an 'error' element is shown" + ); } - + /** - * Create a period after a current opened period fails - * + * create a period with date closing after opening fails. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and we create a new period + * with : dateClosing: 2014-01-01 (before opening) + * with : dateOpening: 2015-01-01 + * with : the last closing motive in list + * Then the response should redirect to period view + */ + public function testCreatePeriodWithClosingBeforeOpeningFails() + { + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Create an accompanying period')->form(); + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue('01-01-2014'); + $form->get(self::OPENING_INPUT) + ->setValue('01-01-2015'); + + $crawler = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.error')->count(), + "an 'error' element is shown" + ); + } + + /** + * create a period with date end between another period must fails. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 + * and we create a new period + * with : dateClosing: 2014-16-01 + * with : dateOpening: 2013-01-01 + * with : the last closing motive in list + * Then the response should not redirect + * and a error element is shown on the response page + */ + public function testCreatePeriodWithDateEndBetweenAnotherPeriodFails() + { + $this->generatePeriods([ + [ + 'openingDate' => '2014-01-01', + 'closingDate' => '2014-12-31', + 'closingMotive' => $this->getRandomClosingMotive(), + ], + ]); + + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Create an accompanying period')->form(); + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue('31-12-2014'); + $form->get(self::OPENING_INPUT) + ->setValue('01-02-2015'); + + $crawlerResponse = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawlerResponse->filter('.error')->count(), + "an 'error' element is shown" + ); + } + + /** + * Create a period with dateOpening between another period must fails. + * + * Given that a person as an accompanying period opened since 2015-01-05 + * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 + * and we create a new period + * with : dateClosing: 2015-01-01 + * with : dateOpening: 2014-06-01 + * with : the last closing motive in list + * Then the response should not redirect + * and a error element is shown on the response page + */ + public function testCreatePeriodWithDateOpeningBetweenAnotherPeriodFails() + { + $this->generatePeriods([ + [ + 'openingDate' => '2014-01-01', + 'closingDate' => '2014-12-31', + 'closingMotive' => $this->getRandomClosingMotive(), + ], + ]); + + $crawler = $this->client->request('GET', '/en/person/' + . $this->person->getId() . '/accompanying-period/create'); + + $form = $crawler->selectButton('Create an accompanying period')->form(); + $form->get(self::CLOSING_MOTIVE_INPUT) + ->setValue($this->getLastValueOnClosingMotive($form)); + $form->get(self::CLOSING_INPUT) + ->setValue('2015-01-01'); + $form->get(self::OPENING_INPUT) + ->setValue('01-06-2014'); + + $crawlerResponse = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawlerResponse->filter('.error')->count(), + "an 'error' element is shown" + ); + } + + /** + * Create a period after a current opened period fails. + * * Given that a person as an accompanying period opened since 2015-01-05 * and we create a new period * with : dateClosing: 2015-03-01 @@ -290,237 +435,153 @@ class AccompanyingPeriodControllerTest extends WebTestCase public function testCreatePeriodWithOpeningAndClosingAfterCurrentFails() { $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - + . $this->person->getId() . '/accompanying-period/create'); + $form = $crawler->selectButton('Create an accompanying period')->form(); $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); + ->setValue($this->getLastValueOnClosingMotive($form)); $form->get(self::CLOSING_INPUT) - ->setValue('01-03-2015'); + ->setValue('01-03-2015'); $form->get(self::OPENING_INPUT) - ->setValue('01-02-2015'); - + ->setValue('01-02-2015'); + $crawler = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawler->filter('.error')->count(), - "an 'error' element is shown"); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the server stay on form page' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.error')->count(), + "an 'error' element is shown" + ); } - - /** - * create a period with date end between another period must fails - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 - * and we create a new period - * with : dateClosing: 2014-16-01 - * with : dateOpening: 2013-01-01 - * with : the last closing motive in list - * Then the response should not redirect - * and a error element is shown on the response page - */ - public function testCreatePeriodWithDateEndBetweenAnotherPeriodFails() - { - $this->generatePeriods(array( - [ - 'openingDate' => '2014-01-01', - 'closingDate' => '2014-12-31', - 'closingMotive' => $this->getRandomClosingMotive() - ] - )); - - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Create an accompanying period')->form();; - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue('31-12-2014'); - $form->get(self::OPENING_INPUT) - ->setValue('01-02-2015'); - - $crawlerResponse = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawlerResponse->filter('.error')->count(), - "an 'error' element is shown"); - } - - /** - * create a period with date closing after opening fails - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and we create a new period - * with : dateClosing: 2014-01-01 (before opening) - * with : dateOpening: 2015-01-01 - * with : the last closing motive in list - * Then the response should redirect to period view - */ - public function testCreatePeriodWithClosingBeforeOpeningFails() - { - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Create an accompanying period')->form(); - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue('01-01-2014'); - $form->get(self::OPENING_INPUT) - ->setValue('01-01-2015'); - - $crawler = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawler->filter('.error')->count(), - "an 'error' element is shown"); - } - - /** - * create a period with date closing and date opening inside another period - * fails - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 - * and we create a new period - * with : dateClosing: 2014-02-01 - * with : dateOpening: 2014-03-01 - * with : the last closing motive in list - * Then the response should not redirect - * and a error element is shown on the response page - */ - public function testCreatePeriodAfterOpeningFails() - { - $this->generatePeriods(array( - [ - 'openingDate' => '2014-01-01', - 'closingDate' => '2014-12-31', - 'closingMotive' => $this->getRandomClosingMotive() - ] - )); - - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Create an accompanying period')->form(); - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue('2014-02-01'); - $form->get(self::OPENING_INPUT) - ->setValue('01-03-2014'); - - $crawlerResponse = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawlerResponse->filter('.error')->count(), - "an 'error' element is shown"); - } - - /** - * Create a period with dateOpening between another period must fails - * - * Given that a person as an accompanying period opened since 2015-01-05 - * and that this person has another accompanying period between 2014-01-01 and 2014-12-31 - * and we create a new period - * with : dateClosing: 2015-01-01 - * with : dateOpening: 2014-06-01 - * with : the last closing motive in list - * Then the response should not redirect - * and a error element is shown on the response page - */ - public function testCreatePeriodWithDateOpeningBetweenAnotherPeriodFails() - { - $this->generatePeriods(array( - [ - 'openingDate' => '2014-01-01', - 'closingDate' => '2014-12-31', - 'closingMotive' => $this->getRandomClosingMotive() - ] - )); - - $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/accompanying-period/create'); - - $form = $crawler->selectButton('Create an accompanying period')->form(); - $form->get(self::CLOSING_MOTIVE_INPUT) - ->setValue($this->getLastValueOnClosingMotive($form)); - $form->get(self::CLOSING_INPUT) - ->setValue('2015-01-01'); - $form->get(self::OPENING_INPUT) - ->setValue('01-06-2014'); - - $crawlerResponse = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the server stay on form page'); - $this->assertGreaterThan(0, $crawlerResponse->filter('.error')->count(), - "an 'error' element is shown"); - } - + /** * @group reopening */ public function testReOpeningPeriod() { // test that re-opening a period which is opened does not work - $this->client->request('GET', - sprintf( - '/fr/person/%d/accompanying-period/%d/re-open', - $this->person->getId(), - $this->person->getOpenedAccompanyingPeriod()->getId() - ) - ); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test an error is returned on a period which cannot be reopened"); - + $this->client->request( + 'GET', + sprintf( + '/fr/person/%d/accompanying-period/%d/re-open', + $this->person->getId(), + $this->person->getOpenedAccompanyingPeriod()->getId() + ) + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test an error is returned on a period which cannot be reopened' + ); + // close the current period $period = $this->person->getOpenedAccompanyingPeriod(); - $period->setClosingDate(new \DateTime('2015-02-05')); + $period->setClosingDate(new DateTime('2015-02-05')); $this->person->close($period); - - $this->generatePeriods(array( + + $this->generatePeriods([ [ 'openingDate' => '2014-01-01', 'closingDate' => '2014-12-31', - 'closingMotive' => $this->getRandomClosingMotive() - ] - )); - + 'closingMotive' => $this->getRandomClosingMotive(), + ], + ]); + $periods = $this->person->getAccompanyingPeriodsOrdered(); /* @var $criteria Criteria */ $criteria = Criteria::create(); //$criteria->where(Criteria::expr()->eq('openingDate', \DateTime::createFromFormat())) $firstPeriod = reset($periods); $lastPeriod = end($periods); - + // test that it is not possible to open the first period in the list - $this->client->request('GET', - sprintf('/fr/person/%d/accompanying-period/%d/re-open', $this->person->getId(), reset($periods)->getId()) - ); - $this->assertEquals(400, $this->client->getResponse()->getStatusCode(), - "Test an error is returned on the first period in the list"); + $this->client->request( + 'GET', + sprintf('/fr/person/%d/accompanying-period/%d/re-open', $this->person->getId(), reset($periods)->getId()) + ); + $this->assertEquals( + 400, + $this->client->getResponse()->getStatusCode(), + 'Test an error is returned on the first period in the list' + ); // test that re-opening the last closed period works - $crawler = $this->client->request('GET', - sprintf('/fr/person/%d/accompanying-period/%d/re-open', $this->person->getId(), end($periods)->getId()) - ); - - $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); - - $links = $crawler->selectLink('Confirmer'); - - $this->assertEquals(1, $links->count(), "test the link 'confirmer' is present"); - - $this->client->click($links->link()); - - $this->assertTrue($this->client->getResponse()->isRedirect(), - "Test the response is a redirection => the period is re-opened"); + $crawler = $this->client->request( + 'GET', + sprintf('/fr/person/%d/accompanying-period/%d/re-open', $this->person->getId(), end($periods)->getId()) + ); + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + $links = $crawler->selectLink('Confirmer'); + + $this->assertEquals(1, $links->count(), "test the link 'confirmer' is present"); + + $this->client->click($links->link()); + + $this->assertTrue( + $this->client->getResponse()->isRedirect(), + 'Test the response is a redirection => the period is re-opened' + ); } -} \ No newline at end of file + + /** + * Given an array of periods (key openingDate, closingDate (optioal), + * closingMotive) generate the periods in the db. + */ + protected function generatePeriods(array $periods) + { + foreach ($periods as $periodDef) { + $period = new AccompanyingPeriod(new DateTime($periodDef['openingDate'])); + + if (array_key_exists('closingDate', $periodDef)) { + if (!array_key_exists('closingMotive', $periodDef)) { + throw new LogicalException('you must define a closing ' + . 'motive into your periods fixtures'); + } + + $period->setClosingDate(new DateTime($periodDef['closingDate'])) + ->setClosingMotive($periodDef['closingMotive']); + } + + $this->person->addAccompanyingPeriod($period); + static::$em->persist($period); + } + + static::$em->flush(); + } + + /** + * Get the last value of a closing motive. + * + * @var \Symfony\Component\DomCrawler\Form The form + * + * @return Chill\PersonBundle\Entity\AccompanyingPeriod The last value of closing + * motive + */ + protected function getLastValueOnClosingMotive(\Symfony\Component\DomCrawler\Form $form) + { + $values = $form->get(self::CLOSING_MOTIVE_INPUT) + ->availableOptionValues(); + + return end($values); + } + + /** + * Get a random closing motive. + * + * @return Chill\PersonBundle\Entity\AccompanyingPeriod The last closing motive + */ + protected function getRandomClosingMotive() + { + $motives = static::$em + ->getRepository('ChillPersonBundle:AccompanyingPeriod\ClosingMotive') + ->findAll(); + + return end($motives); + } +} diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AdminControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AdminControllerTest.php index 04bbfdddc..0eff612fd 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AdminControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AdminControllerTest.php @@ -1,9 +1,20 @@ request('GET', '/{_locale}/admin/person'); } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php index 83fd540fb..a06f0b980 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonAddressControllerTest.php @@ -1,159 +1,150 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\Person; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class PersonAddressControllerTest extends WebTestCase { - /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ - protected $em; - - /** @var Person The person on which the test is executed */ - protected static $person; - /** - * - * @var \Chill\MainBundle\Entity\PostalCode - */ - protected $postalCode; - - /** - * * @var \Symfony\Component\BrowserKit\Client */ protected $client; - + + /** + * @var \Doctrine\ORM\EntityManagerInterface The entity manager + */ + protected $em; + + /** + * @var Person The person on which the test is executed + */ + protected static $person; + + /** + * @var \Chill\MainBundle\Entity\PostalCode + */ + protected $postalCode; + public static function setUpBeforeClass() { static::bootKernel(); - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $center = $em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->findOneBy(['name' => 'Center A']); + self::$person = (new Person()) - ->setLastName("Tested person") - ->setFirstName("Test") + ->setLastName('Tested person') + ->setFirstName('Test') ->setCenter($center) ->setGender(Person::MALE_GENDER); - + $em->persist(self::$person); $em->flush(); } - + /** - * Prepare client and create a random person + * Prepare client and create a random person. */ public function setUp() { static::bootKernel(); - + $this->em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $this->postalCode = $this->em->getRepository('ChillMainBundle:PostalCode') - ->findOneBy(array('code' => 1000)); - - $this->client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); + ->findOneBy(['code' => 1000]); + + $this->client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ]); } - + public static function tearDownAfter() { $this->refreshPerson(); $this->em->remove(self::$person); $this->em->flush(); } - - /** - * Reload the person from the db - */ - protected function refreshPerson() - { - self::$person = $this->em->getRepository('ChillPersonBundle:Person') - ->find(self::$person->getId()); - } - - public function testEmptyList() - { - $crawler = $this->client->request('GET', '/fr/person/'. - self::$person->getId().'/address/list'); - - $this->assertTrue($this->client->getResponse()->isSuccessful()); - - $this->assertEquals(1, $crawler->filter('td:contains("Pas d\'adresse renseignée")') - ->count(), - "assert that a message say 'no address given'"); - - } - + /** * @depends testEmptyList */ public function testCreateAddress() { - $crawler = $this->client->request('GET', '/fr/person/'. - self::$person->getId().'/address/new'); - + $crawler = $this->client->request('GET', '/fr/person/' . + self::$person->getId() . '/address/new'); + $this->assertTrue($this->client->getResponse()->isSuccessful()); - + // get the form and populate the most obvious fields (postcode will come later) - $form = $crawler->filter('.bt-create')->form(array( + $form = $crawler->filter('.bt-create')->form([ 'address[streetAddress1]' => 'Rue de la Paix, 50', - 'address[streetAddress2]' => $this->postalCode->getId(), - 'address[validFrom]' => '15-01-2016' - )); - - // select a random postal code + 'address[streetAddress2]' => $this->postalCode->getId(), + 'address[validFrom]' => '15-01-2016', + ]); + + // select a random postal code $values = $form['address[postCode]']->availableOptionValues(); $form['address[postCode]']->setValue($values[array_rand($values)]); - + $this->client->submit($form); - + $crawler = $this->client->followRedirect(); - - $this->assertRegexp('|/fr/person/[0-9]{1,}/address/list|', - $this->client->getHistory()->current()->getUri(), - "assert that the current page is on |/fr/person/[0-9]{1,}/address/list|"); - $this->assertEquals(1, $crawler + + $this->assertRegexp( + '|/fr/person/[0-9]{1,}/address/list|', + $this->client->getHistory()->current()->getUri(), + 'assert that the current page is on |/fr/person/[0-9]{1,}/address/list|' + ); + $this->assertEquals( + 1, + $crawler ->filter('div.flash_message.success') ->count(), - "Asserting that the response page contains a success flash message"); - $this->assertEquals(1, $crawler + 'Asserting that the response page contains a success flash message' + ); + $this->assertEquals( + 1, + $crawler ->filter('td:contains("Rue de la Paix, 50")') ->count(), - "Asserting that the page contains the new address"); - + 'Asserting that the page contains the new address' + ); } - + + public function testEmptyList() + { + $crawler = $this->client->request('GET', '/fr/person/' . + self::$person->getId() . '/address/list'); + + $this->assertTrue($this->client->getResponse()->isSuccessful()); + + $this->assertEquals( + 1, + $crawler->filter('td:contains("Pas d\'adresse renseignée")') + ->count(), + "assert that a message say 'no address given'" + ); + } + /** * @depends testCreateAddress */ @@ -161,34 +152,48 @@ class PersonAddressControllerTest extends WebTestCase { $this->refreshPerson(); $address = self::$person->getLastAddress(); - - $crawler = $this->client->request('GET', '/fr/person/'.self::$person->getId() - .'/address/'.$address->getId().'/edit'); - + + $crawler = $this->client->request('GET', '/fr/person/' . self::$person->getId() + . '/address/' . $address->getId() . '/edit'); + $this->assertTrue($this->client->getResponse()->isSuccessful()); - - $form = $crawler->filter('.bt-save')->form(array( + + $form = $crawler->filter('.bt-save')->form([ 'address[streetAddress1]' => 'Rue du Trou Normand, 15', - 'address[validFrom]' => '15-01-2015' - )); - + 'address[validFrom]' => '15-01-2015', + ]); + $this->client->submit($form); - + $crawler = $this->client->followRedirect(); - - $this->assertRegexp('|/fr/person/[0-9]{1,}/address/list|', - $this->client->getHistory()->current()->getUri(), - "assert that the current page is on |/fr/person/[0-9]{1,}/address/list|"); - $this->assertGreaterThan(0, $crawler + + $this->assertRegexp( + '|/fr/person/[0-9]{1,}/address/list|', + $this->client->getHistory()->current()->getUri(), + 'assert that the current page is on |/fr/person/[0-9]{1,}/address/list|' + ); + $this->assertGreaterThan( + 0, + $crawler ->filter('div.flash_message.success') ->count(), - "Asserting that the response page contains a success flash message"); - $this->assertEquals(1, $crawler + 'Asserting that the response page contains a success flash message' + ); + $this->assertEquals( + 1, + $crawler ->filter('td:contains("Rue du Trou Normand")') ->count(), - "Asserting that the page contains the new address"); + 'Asserting that the page contains the new address' + ); + } + + /** + * Reload the person from the db. + */ + protected function refreshPerson() + { + self::$person = $this->em->getRepository('ChillPersonBundle:Person') + ->find(self::$person->getId()); } - - - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php index c49c0ea97..8bd600569 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerCreateTest.php @@ -1,46 +1,64 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; +use Chill\MainBundle\Test\PrepareClientTrait; +use DateTime; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\DomCrawler\Form; -use Chill\MainBundle\Test\PrepareClientTrait; /** - * Test creation and deletion for persons + * Test creation and deletion for persons. + * + * @internal + * @coversNothing */ class PersonControllerCreateTest extends WebTestCase { use PrepareClientTrait; - - const FIRSTNAME_INPUT = 'chill_personbundle_person_creation[firstName]'; - const LASTNAME_INPUT = "chill_personbundle_person_creation[lastName]"; - const GENDER_INPUT = "chill_personbundle_person_creation[gender]"; - const BIRTHDATE_INPUT = "chill_personbundle_person_creation[birthdate]"; - const CREATEDATE_INPUT = "chill_personbundle_person_creation[creation_date]"; - const CENTER_INPUT = "chill_personbundle_person_creation[center]"; - - const LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta.Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq."; + + public const BIRTHDATE_INPUT = 'chill_personbundle_person_creation[birthdate]'; + + public const CENTER_INPUT = 'chill_personbundle_person_creation[center]'; + + public const CREATEDATE_INPUT = 'chill_personbundle_person_creation[creation_date]'; + + public const FIRSTNAME_INPUT = 'chill_personbundle_person_creation[firstName]'; + + public const GENDER_INPUT = 'chill_personbundle_person_creation[gender]'; + + public const LASTNAME_INPUT = 'chill_personbundle_person_creation[lastName]'; + + public const LONG_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta.Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosq.'; + + public static function tearDownAfterClass() + { + static::bootKernel(); + $em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager'); + + //remove two people created during test + $jesus = $em->getRepository('ChillPersonBundle:Person') + ->findOneBy(['firstName' => 'God']); + + if (null !== $jesus) { + $em->remove($jesus); + } + + $jesus2 = $em->getRepository('ChillPersonBundle:Person') + ->findOneBy(['firstName' => 'roger']); + + if (null !== $jesus2) { + $em->remove($jesus2); + } + $em->flush(); + } public function setUp() { @@ -48,86 +66,141 @@ class PersonControllerCreateTest extends WebTestCase } /** - * - * @param Form $creationForm - */ - private function fillAValidCreationForm(Form &$creationForm, - $firstname = 'God', $lastname = 'Jesus') - { - $creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname); - $creationForm->get(self::LASTNAME_INPUT)->setValue($lastname); - $creationForm->get(self::GENDER_INPUT)->select("man"); - $date = new \DateTime('1947-02-01'); - $creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('d-m-Y')); - - return $creationForm; - } - - /** - * Test the "add a person" page : test that required elements are present - * + * Test the "add a person" page : test that required elements are present. + * * see https://redmine.champs-libres.coop/projects/chillperson/wiki/Test_plan_for_page_%22add_a_person%22 */ public function testAddAPersonPage() { - $client = $this->client; $crawler = $client->request('GET', '/fr/person/new'); - - $this->assertTrue($client->getResponse()->isSuccessful(), - "The page is accessible at the URL /{_locale}/person/new"); - $form = $crawler->selectButton("Ajouter la personne")->form(); - - $this->assertInstanceOf('Symfony\Component\DomCrawler\Form', $form, - 'The page contains a butto '); - $this->assertTrue($form->has(self::FIRSTNAME_INPUT), - 'The page contains a "firstname" input'); - $this->assertTrue($form->has(self::LASTNAME_INPUT), - 'The page contains a "lastname" input'); - $this->assertTrue($form->has(self::GENDER_INPUT), - 'The page contains a "gender" input'); - $this->assertTrue($form->has(self::BIRTHDATE_INPUT), - 'The page has a "date of birth" input'); - $this->assertTrue($form->has(self::CREATEDATE_INPUT), - 'The page contains a "creation date" input'); - + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page is accessible at the URL /{_locale}/person/new' + ); + $form = $crawler->selectButton('Ajouter la personne')->form(); + + $this->assertInstanceOf( + 'Symfony\Component\DomCrawler\Form', + $form, + 'The page contains a butto ' + ); + $this->assertTrue( + $form->has(self::FIRSTNAME_INPUT), + 'The page contains a "firstname" input' + ); + $this->assertTrue( + $form->has(self::LASTNAME_INPUT), + 'The page contains a "lastname" input' + ); + $this->assertTrue( + $form->has(self::GENDER_INPUT), + 'The page contains a "gender" input' + ); + $this->assertTrue( + $form->has(self::BIRTHDATE_INPUT), + 'The page has a "date of birth" input' + ); + $this->assertTrue( + $form->has(self::CREATEDATE_INPUT), + 'The page contains a "creation date" input' + ); + $genderType = $form->get(self::GENDER_INPUT); - $this->assertEquals('radio', $genderType->getType(), - 'The gender input has radio buttons'); - $this->assertEquals(3, count($genderType->availableOptionValues()), - 'The gender input has three options: man, women and undefined'); - $this->assertTrue(in_array('man', $genderType->availableOptionValues()), - 'gender has "homme" option'); - $this->assertTrue(in_array('woman', $genderType->availableOptionValues()), - 'gender has "femme" option'); + $this->assertEquals( + 'radio', + $genderType->getType(), + 'The gender input has radio buttons' + ); + $this->assertEquals( + 3, + count($genderType->availableOptionValues()), + 'The gender input has three options: man, women and undefined' + ); + $this->assertTrue( + in_array('man', $genderType->availableOptionValues()), + 'gender has "homme" option' + ); + $this->assertTrue( + in_array('woman', $genderType->availableOptionValues()), + 'gender has "femme" option' + ); $this->assertFalse($genderType->hasValue(), 'The gender input is not checked'); - - $today = new \DateTime(); + + $today = new DateTime(); $this->assertEquals($today->format('d-m-Y'), $form->get(self::CREATEDATE_INPUT) - ->getValue(), 'The creation date input has the current date by default'); - + ->getValue(), 'The creation date input has the current date by default'); + return $form; } - + /** - * - * @param Form $form * @depends testAddAPersonPage */ public function testForgedNullGender(Form $form) { $form->get(self::FIRSTNAME_INPUT)->setValue('john'); $form->get(self::LASTNAME_INPUT)->setValue('doe'); - $date = new \DateTime('1947-02-01'); + $date = new DateTime('1947-02-01'); $form->get(self::BIRTHDATE_INPUT)->setValue($date->format('d-m-Y')); $this->client->submit($form); $this->assertResponseStatusCodeSame(500); } - + + /** + * Test if, for a given person if its person view page (at the url + * fr/person/$personID/general) is accessible. + * + * @param int|string $personId The is of the person + * @depends testValidForm + */ + public function testPersonViewAccessible($personId) + { + $client = $this->client; + $client->request('GET', '/fr/person/' . $personId . '/general'); + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The person view page is accessible at the URL' + . '/{_locale}/person/{personID}/general' + ); + } + + public function testReviewExistingDetectionInversedLastNameWithFirstName() + { + $client = $this->client; + + $crawler = $client->request('GET', '/fr/person/new'); + + //test the page is loaded before continuing + $this->assertTrue($client->getResponse()->isSuccessful()); + + $form = $crawler->selectButton('Ajouter la personne')->form(); + $form = $this->fillAValidCreationForm($form, 'Charline', 'dd'); + $client->submit($form); + + $this->assertContains( + 'Depardieu', + $client->getCrawler()->text(), + 'check that the page has detected the lastname of a person existing in database' + ); + + //inversion + $form = $crawler->selectButton('Ajouter la personne')->form(); + $form = $this->fillAValidCreationForm($form, 'dd', 'Charline'); + $client->submit($form); + + $this->assertContains( + 'Depardieu', + $client->getCrawler()->text(), + 'check that the page has detected the lastname of a person existing in database' + ); + } + /** * Test the creation of a valid person. - * - * @param Form $form + * * @return string The id of the created person * @depends testAddAPersonPage */ @@ -136,115 +209,86 @@ class PersonControllerCreateTest extends WebTestCase $this->fillAValidCreationForm($form); $client = $this->client; $client->submit($form); - - $this->assertTrue((bool)$client->getResponse()->isRedirect(), - "a valid form redirect to url /{_locale}/person/{personId}/general/edit"); + + $this->assertTrue( + (bool) $client->getResponse()->isRedirect(), + 'a valid form redirect to url /{_locale}/person/{personId}/general/edit' + ); $client->followRedirect(); - + // visualize regexp here : http://jex.im/regulex/#!embed=false&flags=&re=%2Ffr%2Fperson%2F[1-9][0-9]*%2Fgeneral%2Fedit%24 - $this->assertRegExp('|/fr/person/[1-9][0-9]*/general/edit$|', + $this->assertRegExp( + '|/fr/person/[1-9][0-9]*/general/edit$|', $client->getHistory()->current()->getUri(), - "a valid form redirect to url /{_locale}/person/{personId}/general/edit"); + 'a valid form redirect to url /{_locale}/person/{personId}/general/edit' + ); $regexPersonId = null; - preg_match("/person\/([1-9][0-9]*)\/general\/edit$/", - $client->getHistory()->current()->getUri(), $regexPersonId); + preg_match( + '/person\\/([1-9][0-9]*)\\/general\\/edit$/', + $client->getHistory()->current()->getUri(), + $regexPersonId + ); + return $regexPersonId[1]; } - /** - * Test if, for a given person if its person view page (at the url - * fr/person/$personID/general) is accessible - * - * @param string|int $personId The is of the person - * @depends testValidForm - */ - public function testPersonViewAccessible($personId) - { - $client = $this->client; - $client->request('GET', '/fr/person/'.$personId.'/general'); - - $this->assertTrue($client->getResponse()->isSuccessful(), - "The person view page is accessible at the URL" - . "/{_locale}/person/{personID}/general"); - } - /** * test adding a person with a user with multi center - * is valid + * is valid. */ public function testValidFormWithMultiCenterUser() { $client = $this->getClientAuthenticated('multi_center'); - + $crawler = $client->request('GET', '/fr/person/new'); - - $this->assertTrue($client->getResponse()->isSuccessful(), - "The page is accessible at the URL /{_locale}/person/new"); - $form = $crawler->selectButton("Ajouter la personne")->form(); - + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page is accessible at the URL /{_locale}/person/new' + ); + $form = $crawler->selectButton('Ajouter la personne')->form(); + $this->fillAValidCreationForm($form, 'roger', 'rabbit'); - - $this->assertTrue($form->has(self::CENTER_INPUT), - 'The page contains a "center" input'); + + $this->assertTrue( + $form->has(self::CENTER_INPUT), + 'The page contains a "center" input' + ); $centerInput = $form->get(self::CENTER_INPUT); $availableValues = $centerInput->availableOptionValues(); $lastCenterInputValue = end($availableValues); $centerInput->setValue($lastCenterInputValue); - + $client->submit($form); - - $this->assertTrue($client->getResponse()->isRedirect(), - "a valid form redirect to url /{_locale}/person/{personId}/general/edit"); + + $this->assertTrue( + $client->getResponse()->isRedirect(), + 'a valid form redirect to url /{_locale}/person/{personId}/general/edit' + ); $client->followRedirect(); - $this->assertRegExp('|/fr/person/[1-9][0-9]*/general/edit$|', - $client->getHistory()->current()->getUri(), - "a valid form redirect to url /{_locale}/person/{personId}/general/edit"); - + $this->assertRegExp( + '|/fr/person/[1-9][0-9]*/general/edit$|', + $client->getHistory()->current()->getUri(), + 'a valid form redirect to url /{_locale}/person/{personId}/general/edit' + ); } - - public function testReviewExistingDetectionInversedLastNameWithFirstName() - { - $client = $this->client; - - $crawler = $client->request('GET', '/fr/person/new'); - - //test the page is loaded before continuing - $this->assertTrue($client->getResponse()->isSuccessful()); - - $form = $crawler->selectButton("Ajouter la personne")->form(); - $form = $this->fillAValidCreationForm($form, 'Charline', 'dd'); - $client->submit($form); - - $this->assertContains('Depardieu', $client->getCrawler()->text(), - "check that the page has detected the lastname of a person existing in database"); - - //inversion - $form = $crawler->selectButton("Ajouter la personne")->form(); - $form = $this->fillAValidCreationForm($form, 'dd', 'Charline'); - $client->submit($form); - - $this->assertContains('Depardieu', $client->getCrawler()->text(), - "check that the page has detected the lastname of a person existing in database"); - } - - public static function tearDownAfterClass() - { - static::bootKernel(); - $em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager'); - - //remove two people created during test - $jesus = $em->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('firstName' => 'God')); - if ($jesus !== NULL) { - $em->remove($jesus); - } - - $jesus2 = $em->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('firstName' => 'roger')); - if ($jesus2 !== NULL) { - $em->remove($jesus2); - } - $em->flush(); + + /** + * @param mixed $firstname + * @param mixed $lastname + */ + private function fillAValidCreationForm( + Form &$creationForm, + $firstname = 'God', + $lastname = 'Jesus' + ) { + $creationForm->get(self::FIRSTNAME_INPUT)->setValue($firstname); + $creationForm->get(self::LASTNAME_INPUT)->setValue($lastname); + $creationForm->get(self::GENDER_INPUT)->select('man'); + $date = new DateTime('1947-02-01'); + $creationForm->get(self::BIRTHDATE_INPUT)->setValue($date->format('d-m-Y')); + + return $creationForm; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php index 46fd6dcda..568b73d9c 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerUpdateTest.php @@ -1,306 +1,330 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; //ini_set('memory_limit', '-1'); -use Chill\PersonBundle\Entity\Person; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\MainBundle\Test\PrepareClientTrait; +use Chill\PersonBundle\Entity\Person; +use Closure; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the edition of persons - * + * Test the edition of persons. + * * As I am logged in as "center a_social" * - * @author Julien Fastré + * @internal + * @coversNothing */ class PersonControllerUpdateTest extends WebTestCase { use PrepareClientTrait; - /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ - private $em; - - /** @var Person The person on which the test is executed */ - private $person; - - /** @var string The url using for editing the person's information */ + /** + * @var string The url using for editing the person's information + */ private $editUrl; - /** @var string The url using for seeing the person's information */ - private $viewUrl; - /** - * Prepare client and create a random person + * @var \Doctrine\ORM\EntityManagerInterface The entity manager + */ + private $em; + + /** + * @var Person The person on which the test is executed + */ + private $person; + + /** + * @var string The url using for seeing the person's information + */ + private $viewUrl; + + /** + * Prepare client and create a random person. */ public function setUp() { static::bootKernel(); - + $this->em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $center = $this->em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->findOneBy(['name' => 'Center A']); + $this->person = (new Person()) - ->setLastName("My Beloved") - ->setFirstName("Jesus") + ->setLastName('My Beloved') + ->setFirstName('Jesus') ->setCenter($center) ->setGender(Person::MALE_GENDER); - + $this->em->persist($this->person); $this->em->flush(); - - $this->editUrl = '/en/person/'.$this->person->getId().'/general/edit'; - $this->viewUrl = '/en/person/'.$this->person->getId().'/general'; - + + $this->editUrl = '/en/person/' . $this->person->getId() . '/general/edit'; + $this->viewUrl = '/en/person/' . $this->person->getId() . '/general'; + $this->client = $this->getClientAuthenticated(); } - - /** - * Reload the person from the db - */ - protected function refreshPerson() - { - $this->person = $this->em->getRepository('ChillPersonBundle:Person') - ->find($this->person->getId()); - } - - /** - * Test the edit page are accessible - */ - public function testEditPageIsSuccessful() - { - $this->client->request('GET', $this->editUrl); - $this->assertTrue($this->client->getResponse()->isSuccessful(), - "The person edit form is accessible"); - } - - /** - * Test the configurable fields are present - * - * @group configurable_fields - */ - public function testHiddenFielsArePresent() - { - $crawler = $this->client->request('GET', $this->editUrl); - - $configurables = array('placeOfBirth', 'phonenumber', 'email', - 'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus'); - $form = $crawler->selectButton('Submit')->form(); //; - - foreach($configurables as $key) { - $this->assertTrue($form->has('chill_personbundle_person['.$key.']')); - } - } - - /** - * Test if the edit page of a given person is not accessible for a user - * of another center of the person - */ - public function testEditPageDeniedForUnauthorized_OutsideCenter() - { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center b_social', - 'PHP_AUTH_PW' => 'password', - )); - - $client->request('GET', $this->editUrl); - $this->assertEquals(403, $client->getResponse()->getStatusCode(), - "The edit page of a person of a center A must not be accessible for user of center B"); - } - - /** - * Test the edit page of a given person are not accessible for an - * administrative user - */ - public function testEditPageDeniedForUnauthorized_InsideCenter() - { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_administrative', - 'PHP_AUTH_PW' => 'password', - )); - - $client->request('GET', $this->editUrl); - $this->assertEquals(403, $client->getResponse()->getStatusCode()); - } - - /** - * Test the edition of a field - * - * Given I fill the field with $value - * And I submit the form - * Then I am redirected to the 'general' page - * And the person is updated in the db - * - * @dataProvider validTextFieldsProvider - * @param string $field - * @param string $value - * @param \Closure $callback - */ - public function testEditTextField($field, $value, \Closure $callback) - { - $crawler = $this->client->request('GET', $this->editUrl); - - $form = $crawler->selectButton('Submit') - ->form(); - //transform countries into value if needed - switch ($field) { - case 'nationality': - case 'countryOfBirth': - if ($value !== NULL) { - $country = $this->em->getRepository('ChillMainBundle:Country') - ->findOneByCountryCode($value); - $transformedValue = $country->getId(); - } else { - $transformedValue = NULL; - } - break; - default: - $transformedValue = $value; - } - - $form->get('chill_personbundle_person['.$field. ']') - ->setValue($transformedValue); - - $this->client->submit($form); - $this->refreshPerson(); - - $this->assertTrue($this->client->getResponse()->isRedirect($this->viewUrl), - 'the page is redirected to general view'); - $this->assertEquals($value, $callback($this->person), - 'the value '.$field.' is updated in db'); - $crawler = $this->client->followRedirect(); - $this->assertGreaterThan(0, $crawler->filter('.success')->count(), - 'a element .success is shown'); - - if($field == 'birthdate' or $field == 'memo' or $field == 'countryOfBirth' or $field == 'nationality' - or $field == 'gender') { - // we do not perform test on the web page contents. - } else { - $this->assertGreaterThan(0, $crawler->filter('html:contains("'.$value.'")')->count()); - } - } - - public function testEditLanguages() - { - $crawler = $this->client->request('GET', $this->editUrl); - $selectedLanguages = array('en', 'an', 'bbj'); - - $form = $crawler->selectButton('Submit') - ->form(); - $form->get('chill_personbundle_person[spokenLanguages]') - ->setValue($selectedLanguages); - - $this->client->submit($form); - $this->refreshPerson(); - - $this->assertTrue($this->client->getResponse()->isRedirect($this->viewUrl), - 'the page is redirected to /general view'); - //retrieve languages codes present in person - foreach($this->person->getSpokenLanguages() as $lang){ - $languagesCodesPresents[] = $lang->getId(); - } - $this->assertEquals(asort($selectedLanguages), asort($languagesCodesPresents), - 'the person speaks the expected languages'); - } - - - /** - * Test tbe detection of invalid data during the update procedure - * - * @dataProvider providesInvalidFieldsValues - * @param string $field - * @param string $value - */ - public function testInvalidFields($field, $value) - { - $crawler = $this->client->request('GET', $this->editUrl); - - $form = $crawler->selectButton('Submit') - ->form(); - $form->get('chill_personbundle_person['.$field.']') - ->setValue($value); - - $crawler = $this->client->submit($form); - - $this->assertFalse($this->client->getResponse()->isRedirect(), - 'the page is not redirected to /general'); - $this->assertGreaterThan(0, $crawler->filter('.error')->count(), - 'a element .error is shown'); - } - - /** - * provide valid values to test, with field name and - * a function to find the value back from person entity - * - * @return mixed[] - */ - public function validTextFieldsProvider() - { - return array( - ['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ], - ['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ], - ['placeOfBirth', 'none place', function(Person $person) { return $person->getPlaceOfBirth(); }], - ['birthdate', '15-12-1980', function(Person $person) { return $person->getBirthdate()->format('d-m-Y'); }], - ['phonenumber', '0123456789', function(Person $person) { return $person->getPhonenumber(); }], - ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }], - ['countryOfBirth', 'BE', function(Person $person) { return $person->getCountryOfBirth()->getCountryCode(); }], - ['nationality', 'FR', function(Person $person) { return $person->getNationality()->getCountryCode(); }], - ['placeOfBirth', '', function(Person $person) { return $person->getPlaceOfBirth(); }], - ['birthdate', '', function(Person $person) { return $person->getBirthdate(); }], - ['phonenumber', '', function(Person $person) { return $person->getPhonenumber(); }], - ['memo', '', function(Person $person) { return $person->getMemo(); }], - ['countryOfBirth', NULL, function(Person $person) { return $person->getCountryOfBirth(); }], - ['nationality', NULL, function(Person $person) { return $person->getNationality(); }], - ['gender', Person::FEMALE_GENDER, function(Person $person) { return $person->getGender(); }], - ['maritalStatus', NULL, function(Person $person) {return $person->getMaritalStatus(); }] - ); - } - - public function providesInvalidFieldsValues() - { - return array( - ['firstName', $this->getVeryLongText()], - ['lastName', $this->getVeryLongText()], - ['firstName', ''], - ['lastName', ''], - ['birthdate', 'false date'] - ); - } - public function tearDown() { $this->refreshPerson(); $this->em->remove($this->person); $this->em->flush(); } - + + public function providesInvalidFieldsValues() + { + return [ + ['firstName', $this->getVeryLongText()], + ['lastName', $this->getVeryLongText()], + ['firstName', ''], + ['lastName', ''], + ['birthdate', 'false date'], + ]; + } + + public function testEditLanguages() + { + $crawler = $this->client->request('GET', $this->editUrl); + $selectedLanguages = ['en', 'an', 'bbj']; + + $form = $crawler->selectButton('Submit') + ->form(); + $form->get('chill_personbundle_person[spokenLanguages]') + ->setValue($selectedLanguages); + + $this->client->submit($form); + $this->refreshPerson(); + + $this->assertTrue( + $this->client->getResponse()->isRedirect($this->viewUrl), + 'the page is redirected to /general view' + ); + //retrieve languages codes present in person + foreach ($this->person->getSpokenLanguages() as $lang) { + $languagesCodesPresents[] = $lang->getId(); + } + $this->assertEquals( + asort($selectedLanguages), + asort($languagesCodesPresents), + 'the person speaks the expected languages' + ); + } + + /** + * Test the edit page of a given person are not accessible for an + * administrative user. + */ + public function testEditPageDeniedForUnauthorizedInsideCenter() + { + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_administrative', + 'PHP_AUTH_PW' => 'password', + ]); + + $client->request('GET', $this->editUrl); + $this->assertEquals(403, $client->getResponse()->getStatusCode()); + } + + /** + * Test if the edit page of a given person is not accessible for a user + * of another center of the person. + */ + public function testEditPageDeniedForUnauthorizedOutsideCenter() + { + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center b_social', + 'PHP_AUTH_PW' => 'password', + ]); + + $client->request('GET', $this->editUrl); + $this->assertEquals( + 403, + $client->getResponse()->getStatusCode(), + 'The edit page of a person of a center A must not be accessible for user of center B' + ); + } + + /** + * Test the edit page are accessible. + */ + public function testEditPageIsSuccessful() + { + $this->client->request('GET', $this->editUrl); + $this->assertTrue( + $this->client->getResponse()->isSuccessful(), + 'The person edit form is accessible' + ); + } + + /** + * Test the edition of a field. + * + * Given I fill the field with $value + * And I submit the form + * Then I am redirected to the 'general' page + * And the person is updated in the db + * + * @dataProvider validTextFieldsProvider + * + * @param string $field + * @param string $value + */ + public function testEditTextField($field, $value, Closure $callback) + { + $crawler = $this->client->request('GET', $this->editUrl); + + $form = $crawler->selectButton('Submit') + ->form(); + //transform countries into value if needed + switch ($field) { + case 'nationality': + case 'countryOfBirth': + if (null !== $value) { + $country = $this->em->getRepository('ChillMainBundle:Country') + ->findOneByCountryCode($value); + $transformedValue = $country->getId(); + } else { + $transformedValue = null; + } + + break; + + default: + $transformedValue = $value; + } + + $form->get('chill_personbundle_person[' . $field . ']') + ->setValue($transformedValue); + + $this->client->submit($form); + $this->refreshPerson(); + + $this->assertTrue( + $this->client->getResponse()->isRedirect($this->viewUrl), + 'the page is redirected to general view' + ); + $this->assertEquals( + $value, + $callback($this->person), + 'the value ' . $field . ' is updated in db' + ); + + $crawler = $this->client->followRedirect(); + $this->assertGreaterThan( + 0, + $crawler->filter('.success')->count(), + 'a element .success is shown' + ); + + if ('birthdate' == $field or 'memo' == $field or 'countryOfBirth' == $field or 'nationality' == $field + or 'gender' == $field) { + // we do not perform test on the web page contents. + } else { + $this->assertGreaterThan(0, $crawler->filter('html:contains("' . $value . '")')->count()); + } + } + + /** + * Test the configurable fields are present. + * + * @group configurable_fields + */ + public function testHiddenFielsArePresent() + { + $crawler = $this->client->request('GET', $this->editUrl); + + $configurables = ['placeOfBirth', 'phonenumber', 'email', + 'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus', ]; + $form = $crawler->selectButton('Submit')->form(); //; + + foreach ($configurables as $key) { + $this->assertTrue($form->has('chill_personbundle_person[' . $key . ']')); + } + } + + /** + * Test tbe detection of invalid data during the update procedure. + * + * @dataProvider providesInvalidFieldsValues + * + * @param string $field + * @param string $value + */ + public function testInvalidFields($field, $value) + { + $crawler = $this->client->request('GET', $this->editUrl); + + $form = $crawler->selectButton('Submit') + ->form(); + $form->get('chill_personbundle_person[' . $field . ']') + ->setValue($value); + + $crawler = $this->client->submit($form); + + $this->assertFalse( + $this->client->getResponse()->isRedirect(), + 'the page is not redirected to /general' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.error')->count(), + 'a element .error is shown' + ); + } + + /** + * provide valid values to test, with field name and + * a function to find the value back from person entity. + * + * @return mixed[] + */ + public function validTextFieldsProvider() + { + return [ + ['firstName', 'random Value', function (Person $person) { return $person->getFirstName(); }], + ['lastName', 'random Value', function (Person $person) { return $person->getLastName(); }], + ['placeOfBirth', 'none place', function (Person $person) { return $person->getPlaceOfBirth(); }], + ['birthdate', '15-12-1980', function (Person $person) { return $person->getBirthdate()->format('d-m-Y'); }], + ['phonenumber', '0123456789', function (Person $person) { return $person->getPhonenumber(); }], + ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function (Person $person) { return $person->getMemo(); }], + ['countryOfBirth', 'BE', function (Person $person) { return $person->getCountryOfBirth()->getCountryCode(); }], + ['nationality', 'FR', function (Person $person) { return $person->getNationality()->getCountryCode(); }], + ['placeOfBirth', '', function (Person $person) { return $person->getPlaceOfBirth(); }], + ['birthdate', '', function (Person $person) { return $person->getBirthdate(); }], + ['phonenumber', '', function (Person $person) { return $person->getPhonenumber(); }], + ['memo', '', function (Person $person) { return $person->getMemo(); }], + ['countryOfBirth', null, function (Person $person) { return $person->getCountryOfBirth(); }], + ['nationality', null, function (Person $person) { return $person->getNationality(); }], + ['gender', Person::FEMALE_GENDER, function (Person $person) { return $person->getGender(); }], + ['maritalStatus', null, function (Person $person) {return $person->getMaritalStatus(); }], + ]; + } + + /** + * Reload the person from the db. + */ + protected function refreshPerson() + { + $this->person = $this->em->getRepository('ChillPersonBundle:Person') + ->find($this->person->getId()); + } + private function getVeryLongText() { - return << - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; @@ -23,189 +12,211 @@ namespace Chill\PersonBundle\Tests\Controller; //ini_set('memory_limit', '-1'); use Chill\PersonBundle\Entity\Person; +use Closure; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test the edition of persons - * + * Test the edition of persons. + * * As I am logged in as "center a_social" * - * @author Julien Fastré + * @internal + * @coversNothing */ class PersonControllerUpdateWithHiddenFieldsTest extends WebTestCase { - /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ - private $em; - - /** @var Person The person on which the test is executed */ - private $person; - - /** @var string The url using for editing the person's information */ + /** + * @var string The url using for editing the person's information + */ private $editUrl; - /** @var string The url using for seeing the person's information */ - private $viewUrl; - /** - * Prepare client and create a random person + * @var \Doctrine\ORM\EntityManagerInterface The entity manager + */ + private $em; + + /** + * @var Person The person on which the test is executed + */ + private $person; + + /** + * @var string The url using for seeing the person's information + */ + private $viewUrl; + + /** + * Prepare client and create a random person. */ public function setUp() { - static::bootKernel(array('environment' => 'test_with_hidden_fields')); - + static::bootKernel(['environment' => 'test_with_hidden_fields']); + $this->em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $center = $this->em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->findOneBy(['name' => 'Center A']); + $this->person = (new Person()) - ->setLastName("My Beloved") - ->setFirstName("Jesus") + ->setLastName('My Beloved') + ->setFirstName('Jesus') ->setCenter($center) ->setGender(Person::MALE_GENDER); - + $this->em->persist($this->person); $this->em->flush(); - - $this->editUrl = '/en/person/'.$this->person->getId().'/general/edit'; - $this->viewUrl = '/en/person/'.$this->person->getId().'/general'; - + + $this->editUrl = '/en/person/' . $this->person->getId() . '/general/edit'; + $this->viewUrl = '/en/person/' . $this->person->getId() . '/general'; + $this->client = static::createClient( - array( - 'environment' => 'test_with_hidden_fields' - ), - array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - ) - ); - } - - /** - * Reload the person from the db - */ - protected function refreshPerson() - { - $this->person = $this->em->getRepository('ChillPersonBundle:Person') - ->find($this->person->getId()); - } - - /** - * Test the edit page are accessible - */ - public function testEditPageIsSuccessful() - { - $this->client->request('GET', $this->editUrl); - $this->assertTrue($this->client->getResponse()->isSuccessful(), - "The person edit form is accessible"); - } - - /** - * Test the configurable fields are absent - * - * @group configurable_fields - */ - public function testHiddenFielsAreAbsent() - { - $crawler = $this->client->request('GET', $this->editUrl); - - $configurables = array('placeOfBirth', 'phonenumber', 'email', - 'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus'); - $form = $crawler->selectButton('Submit')->form(); //; - - foreach($configurables as $key) { - $this->assertFalse($form->has('chill_personbundle_person['.$key.']')); - } - } - - /** - * Test the edition of a field - * - * Given I fill the field with $value - * And I submit the form - * Then I am redirected to the 'general' page - * And the person is updated in the db - * - * @dataProvider validTextFieldsProvider - * @param string $field - * @param string $value - * @param \Closure $callback - */ - public function testEditTextField($field, $value, \Closure $callback) - { - $crawler = $this->client->request('GET', $this->editUrl); - - $form = $crawler->selectButton('Submit') - ->form(); - //transform countries into value if needed - switch ($field) { - case 'nationality': - case 'countryOfBirth': - if ($value !== NULL) { - $country = $this->em->getRepository('ChillMainBundle:Country') - ->findOneByCountryCode($value); - $transformedValue = $country->getId(); - } else { - $transformedValue = NULL; - } - break; - default: - $transformedValue = $value; - } - - $form->get('chill_personbundle_person['.$field. ']') - ->setValue($transformedValue); - - $this->client->submit($form); - $this->refreshPerson(); - - $this->assertTrue($this->client->getResponse()->isRedirect($this->viewUrl), - 'the page is redirected to general view'); - $this->assertEquals($value, $callback($this->person), - 'the value '.$field.' is updated in db'); - - $crawler = $this->client->followRedirect(); - $this->assertGreaterThan(0, $crawler->filter('.success')->count(), - 'a element .success is shown'); - - if($field == 'birthdate' or $field == 'memo' or $field == 'countryOfBirth' or $field == 'nationality' - or $field == 'gender') { - // we do not perform test on the web page contents. - } else { - $this->assertGreaterThan(0, $crawler->filter('html:contains("'.$value.'")')->count()); - } - } - - /** - * provide valid values to test, with field name and - * a function to find the value back from person entity - * - * @return mixed[] - */ - public function validTextFieldsProvider() - { - return array( - ['firstName', 'random Value', function(Person $person) { return $person->getFirstName(); } ], - ['lastName' , 'random Value', function(Person $person) { return $person->getLastName(); } ], - ['birthdate', '15-12-1980', function(Person $person) { return $person->getBirthdate()->format('d-m-Y'); }], - ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function(Person $person) { return $person->getMemo(); }], - ['birthdate', '', function(Person $person) { return $person->getBirthdate(); }], - ['gender', Person::FEMALE_GENDER, function(Person $person) { return $person->getGender(); }], + [ + 'environment' => 'test_with_hidden_fields', + ], + [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ] ); } - + public function tearDown() { $this->refreshPerson(); $this->em->remove($this->person); $this->em->flush(); } - + + /** + * Test the edit page are accessible. + */ + public function testEditPageIsSuccessful() + { + $this->client->request('GET', $this->editUrl); + $this->assertTrue( + $this->client->getResponse()->isSuccessful(), + 'The person edit form is accessible' + ); + } + + /** + * Test the edition of a field. + * + * Given I fill the field with $value + * And I submit the form + * Then I am redirected to the 'general' page + * And the person is updated in the db + * + * @dataProvider validTextFieldsProvider + * + * @param string $field + * @param string $value + */ + public function testEditTextField($field, $value, Closure $callback) + { + $crawler = $this->client->request('GET', $this->editUrl); + + $form = $crawler->selectButton('Submit') + ->form(); + //transform countries into value if needed + switch ($field) { + case 'nationality': + case 'countryOfBirth': + if (null !== $value) { + $country = $this->em->getRepository('ChillMainBundle:Country') + ->findOneByCountryCode($value); + $transformedValue = $country->getId(); + } else { + $transformedValue = null; + } + + break; + + default: + $transformedValue = $value; + } + + $form->get('chill_personbundle_person[' . $field . ']') + ->setValue($transformedValue); + + $this->client->submit($form); + $this->refreshPerson(); + + $this->assertTrue( + $this->client->getResponse()->isRedirect($this->viewUrl), + 'the page is redirected to general view' + ); + $this->assertEquals( + $value, + $callback($this->person), + 'the value ' . $field . ' is updated in db' + ); + + $crawler = $this->client->followRedirect(); + $this->assertGreaterThan( + 0, + $crawler->filter('.success')->count(), + 'a element .success is shown' + ); + + if ('birthdate' == $field or 'memo' == $field or 'countryOfBirth' == $field or 'nationality' == $field + or 'gender' == $field) { + // we do not perform test on the web page contents. + } else { + $this->assertGreaterThan(0, $crawler->filter('html:contains("' . $value . '")')->count()); + } + } + + /** + * Test the configurable fields are absent. + * + * @group configurable_fields + */ + public function testHiddenFielsAreAbsent() + { + $crawler = $this->client->request('GET', $this->editUrl); + + $configurables = ['placeOfBirth', 'phonenumber', 'email', + 'countryOfBirth', 'nationality', 'spokenLanguages', 'maritalStatus', ]; + $form = $crawler->selectButton('Submit')->form(); //; + + foreach ($configurables as $key) { + $this->assertFalse($form->has('chill_personbundle_person[' . $key . ']')); + } + } + + /** + * provide valid values to test, with field name and + * a function to find the value back from person entity. + * + * @return mixed[] + */ + public function validTextFieldsProvider() + { + return [ + ['firstName', 'random Value', function (Person $person) { return $person->getFirstName(); }], + ['lastName', 'random Value', function (Person $person) { return $person->getLastName(); }], + ['birthdate', '15-12-1980', function (Person $person) { return $person->getBirthdate()->format('d-m-Y'); }], + ['memo', 'jfkdlmq jkfldmsq jkmfdsq', function (Person $person) { return $person->getMemo(); }], + ['birthdate', '', function (Person $person) { return $person->getBirthdate(); }], + ['gender', Person::FEMALE_GENDER, function (Person $person) { return $person->getGender(); }], + ]; + } + + /** + * Reload the person from the db. + */ + protected function refreshPerson() + { + $this->person = $this->em->getRepository('ChillPersonBundle:Person') + ->find($this->person->getId()); + } + private function getVeryLongText() { - return << +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\Person; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * @author Julien Fastré - * @author Marc Ducobu + * @internal + * @coversNothing */ class PersonControllerViewTest extends WebTestCase { - /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ + /** + * @var \Doctrine\ORM\EntityManagerInterface The entity manager + */ private $em; - - /** @var Person A person used on which to run the test */ + + /** + * @var Person A person used on which to run the test + */ private $person; - /** @var String The url to view the person details */ + /** + * @var string The url to view the person details + */ private $viewUrl; - + public function setUp() { static::bootKernel(); - + $this->em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $center = $this->em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->findOneBy(['name' => 'Center A']); + $this->person = (new Person()) - ->setLastName("Tested Person") - ->setFirstName("Réginald") + ->setLastName('Tested Person') + ->setFirstName('Réginald') ->setCenter($center) ->setGender(Person::MALE_GENDER); - + $this->em->persist($this->person); $this->em->flush(); - - $this->viewUrl = '/en/person/'.$this->person->getId().'/general'; + + $this->viewUrl = '/en/person/' . $this->person->getId() . '/general'; } - + + public function tearDown() + { + $this->refreshPerson(); + $this->em->remove($this->person); + $this->em->flush(); + } + /** - * Test if the view page is accessible - * + * Test if the view page is accessible. + * * @group configurable_fields */ public function testViewPerson() { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); - + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ]); + $crawler = $client->request('GET', $this->viewUrl); $response = $client->getResponse(); @@ -83,37 +86,32 @@ class PersonControllerViewTest extends WebTestCase $this->assertContains('Langues parlées', $crawler->text()); $this->assertContains(/* Etat */ 'civil', $crawler->text()); } - + /** * Test if the view page of a given person is not accessible for a user - * of another center of the person + * of another center of the person. */ public function testViewPersonAccessDeniedForUnauthorized() { - $client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center b_social', - 'PHP_AUTH_PW' => 'password', - )); - + $client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center b_social', + 'PHP_AUTH_PW' => 'password', + ]); + $client->request('GET', $this->viewUrl); - $this->assertEquals(403, $client->getResponse()->getStatusCode(), - "The view page of a person of a center A must not be accessible for user of center B"); + $this->assertEquals( + 403, + $client->getResponse()->getStatusCode(), + 'The view page of a person of a center A must not be accessible for user of center B' + ); } - + /** - * Reload the person from the db + * Reload the person from the db. */ - protected function refreshPerson() + protected function refreshPerson() { $this->person = $this->em->getRepository('ChillPersonBundle:Person') ->find($this->person->getId()); } - - public function tearDown() - { - $this->refreshPerson(); - $this->em->remove($this->person); - $this->em->flush(); - } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php index 2ace5c1da..29ae034c0 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonControllerViewWithHiddenFieldsTest.php @@ -1,83 +1,86 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Chill\PersonBundle\Entity\Person; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * @author Julien Fastré - * @author Marc Ducobu + * @internal + * @coversNothing */ class PersonControllerViewTestWithHiddenFields extends WebTestCase { - /** @var \Doctrine\ORM\EntityManagerInterface The entity manager */ + /** + * @var \Doctrine\ORM\EntityManagerInterface The entity manager + */ private $em; - - /** @var Person A person used on which to run the test */ + + /** + * @var Person A person used on which to run the test + */ private $person; - /** @var String The url to view the person details */ + /** + * @var string The url to view the person details + */ private $viewUrl; - + public function setUp() { - static::bootKernel(array('environment' => 'test_with_hidden_fields')); - + static::bootKernel(['environment' => 'test_with_hidden_fields']); + $this->em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - + $center = $this->em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - + ->findOneBy(['name' => 'Center A']); + $this->person = (new Person()) - ->setLastName("Tested Person") - ->setFirstName("Réginald") + ->setLastName('Tested Person') + ->setFirstName('Réginald') ->setCenter($center) ->setGender(Person::MALE_GENDER); - + $this->em->persist($this->person); $this->em->flush(); - - $this->viewUrl = '/en/person/'.$this->person->getId().'/general'; + + $this->viewUrl = '/en/person/' . $this->person->getId() . '/general'; } - + + public function tearDown() + { + $this->refreshPerson(); + $this->em->remove($this->person); + $this->em->flush(); + } + /** - * Test if the view page is accessible - * + * Test if the view page is accessible. + * * @group configurable_fields */ public function testViewPerson() { $client = static::createClient( - array('environment' => 'test_with_hidden_fields'), - array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - 'HTTP_ACCEPT_LANGUAGE' => 'fr' - ) - ); - + ['environment' => 'test_with_hidden_fields'], + [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + 'HTTP_ACCEPT_LANGUAGE' => 'fr', + ] + ); + $crawler = $client->request('GET', $this->viewUrl); $response = $client->getResponse(); - + $this->assertTrue($response->isSuccessful()); $this->assertGreaterThan(0, $crawler->filter('html:contains("Tested Person")')->count()); @@ -87,21 +90,13 @@ class PersonControllerViewTestWithHiddenFields extends WebTestCase $this->assertNotContains('Langues parlées', $crawler->text()); $this->assertNotContains(/* Etat */ 'civil', $crawler->text()); } - + /** - * Reload the person from the db + * Reload the person from the db. */ - protected function refreshPerson() + protected function refreshPerson() { $this->person = $this->em->getRepository('ChillPersonBundle:Person') ->find($this->person->getId()); } - - public function tearDown() - { - $this->refreshPerson(); - $this->em->remove($this->person); - $this->em->flush(); - } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php index 1292ecbeb..774329556 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php @@ -1,10 +1,21 @@ get('doctrine.orm.entity_manager'); $center = $this->em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); + ->findOneBy(['name' => 'Center A']); $this->person = (new Person()) - ->setLastName("Tested Persan") - ->setFirstName("Réginal") + ->setLastName('Tested Persan') + ->setFirstName('Réginal') ->setCenter($center) ->setGender(Person::MALE_GENDER); $this->em->persist($this->person); $this->person2 = (new Person()) - ->setLastName("Tested Person") - ->setFirstName("Réginald") + ->setLastName('Tested Person') + ->setFirstName('Réginald') ->setCenter($center) ->setGender(Person::MALE_GENDER); $this->em->persist($this->person2); @@ -36,12 +47,12 @@ class PersonDuplicateControllerViewTest extends WebTestCase public function testViewDuplicatePerson() { - $client = static::createClient(array(), array( + $client = static::createClient([], [ 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); + 'PHP_AUTH_PW' => 'password', + ]); - $crawler = $client->request('GET', '/en/person/'.$this->person->getId().'/duplicate/view'); + $crawler = $client->request('GET', '/en/person/' . $this->person->getId() . '/duplicate/view'); $response = $client->getResponse(); $this->assertTrue($response->isSuccessful()); @@ -49,15 +60,15 @@ class PersonDuplicateControllerViewTest extends WebTestCase $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginal")')->count()); $this->assertGreaterThan(0, $crawler->filter('html:contains("Réginald")')->count()); - $crawler = $client->request('GET', '/en/person/'.$this->person->getId().'/duplicate/'.$this->person2->getId().'/confirm'); + $crawler = $client->request('GET', '/en/person/' . $this->person->getId() . '/duplicate/' . $this->person2->getId() . '/confirm'); $response = $client->getResponse(); $this->assertTrue($response->isSuccessful()); $this->assertGreaterThan(0, $crawler->filter('html:contains("Old person")')->count()); $this->assertGreaterThan(0, $crawler->filter('html:contains("New person")')->count()); - $crawler = $client->request('POST', '/en/person/'.$this->person->getId().'/duplicate/'.$this->person2->getId().'/confirm', [ - 'chill_personbundle_person_confirm_duplicate[confirm]' => 1 + $crawler = $client->request('POST', '/en/person/' . $this->person->getId() . '/duplicate/' . $this->person2->getId() . '/confirm', [ + 'chill_personbundle_person_confirm_duplicate[confirm]' => 1, ]); $response = $client->getResponse(); $this->assertTrue($response->isSuccessful()); diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php index 03fddab41..b764914c8 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/AccompanyingPeriodTest.php @@ -1,36 +1,39 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Entity; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; +use DateTime; +use DateTimeInterface; +/** + * @internal + * @coversNothing + */ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase { + public function testClosingEqualOpening() + { + $datetime = new DateTime('now'); + + $period = new AccompanyingPeriod($datetime); + $period->setClosingDate($datetime); + + $this->assertTrue($period->isClosingAfterOpening()); + } + public function testClosingIsAfterOpeningConsistency() { - $datetime1 = new \DateTime('now'); - $datetime2 = new \DateTime('tomorrow'); + $datetime1 = new DateTime('now'); + $datetime2 = new DateTime('tomorrow'); $period = new AccompanyingPeriod($datetime1); $period->setClosingDate($datetime2); @@ -42,8 +45,8 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase public function testClosingIsBeforeOpeningConsistency() { - $datetime1 = new \DateTime('tomorrow'); - $datetime2 = new \DateTime('now'); + $datetime1 = new DateTime('tomorrow'); + $datetime2 = new DateTime('now'); $period = new AccompanyingPeriod($datetime1); $period->setClosingDate($datetime2); @@ -51,37 +54,27 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $this->assertFalse($period->isClosingAfterOpening()); } - public function testClosingEqualOpening() + public function testIsClosed() { - $datetime = new \DateTime('now'); + $period = new AccompanyingPeriod(new DateTime()); + $period->setClosingDate(new DateTime('tomorrow')); - $period = new AccompanyingPeriod($datetime); - $period->setClosingDate($datetime); - - $this->assertTrue($period->isClosingAfterOpening()); + $this->assertFalse($period->isOpen()); } public function testIsOpen() { - $period = new AccompanyingPeriod(new \DateTime()); + $period = new AccompanyingPeriod(new DateTime()); $this->assertTrue($period->isOpen()); } - public function testIsClosed() - { - $period = new AccompanyingPeriod(new \DateTime()); - $period->setClosingDate(new \DateTime('tomorrow')); - - $this->assertFalse($period->isOpen()); - } - public function testPersonPeriod() { $person = new Person(); $person2 = new Person(); $person3 = new Person(); - $period = new AccompanyingPeriod(new \DateTime()); + $period = new AccompanyingPeriod(new DateTime()); $period->addPerson($person); $period->addPerson($person2); @@ -99,7 +92,7 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase $participationL = $period->removePerson($person); $this->assertSame($participationL, $participation); - $this->assertTrue($participation->getEndDate() instanceof \DateTimeInterface); + $this->assertTrue($participation->getEndDate() instanceof DateTimeInterface); $participation = $period->getOpenParticipationContainsPerson($person); $this->assertNull($participation); diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php index b1e6d6971..db519420d 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Entity/PersonTest.php @@ -1,166 +1,139 @@ , * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Entity; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\MainBundle\Entity\Address; +use Chill\PersonBundle\Entity\AccompanyingPeriod; +use Chill\PersonBundle\Entity\Person; use DateInterval; use DateTime; use Generator; /** - * Unit tests for the person Entity + * Unit tests for the person Entity. + * + * @internal + * @coversNothing */ class PersonTest extends \PHPUnit\Framework\TestCase { - /** - * Test the creation of an accompanying, its closure and the access to - * the current accompaniying period via the getCurrentAccompanyingPeriod - * function. - */ - public function testGetCurrentAccompanyingPeriod() + public function dateProvider(): Generator { - $d = new \DateTime('yesterday'); - $p = new Person($d); - - $period = $p->getCurrentAccompanyingPeriod(); - - $this->assertInstanceOf('Chill\PersonBundle\Entity\AccompanyingPeriod', $period); - $this->assertTrue($period->isOpen()); - $this->assertEquals($d, $period->getOpeningDate()); - - //close and test - $period->setClosingDate(new \DateTime('tomorrow')); - - $shouldBeNull = $p->getCurrentAccompanyingPeriod(); - $this->assertNull($shouldBeNull); + yield [(DateTime::createFromFormat('Y-m-d', '2021-01-05'))->settime(0, 0)]; + + yield [(DateTime::createFromFormat('Y-m-d', '2021-02-05'))->settime(0, 0)]; + + yield [(DateTime::createFromFormat('Y-m-d', '2021-03-05'))->settime(0, 0)]; } - + + /** + * Test if the getAccompanyingPeriodsOrdered function, for periods + * starting at the same time order regarding to the closing date. + */ + public function testAccompanyingPeriodOrderSameDateOpening() + { + $d = new DateTime('2013/2/1'); + $p = new Person($d); + + $g = new DateTime('2013/4/1'); + $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); + $p->close($period); + + $f = new DateTime('2013/2/1'); + $p->open(new AccompanyingPeriod($f)); + + $e = new DateTime('2013/3/1'); + $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); + $p->close($period); + + $r = $p->getAccompanyingPeriodsOrdered(); + + $date = $r[0]->getClosingDate()->format('Y-m-d'); + + $this->assertEquals($date, '2013-03-01'); + } + /** * Test if the getAccompanyingPeriodsOrdered function return a list of * periods ordered ascendency. */ public function testAccompanyingPeriodOrderWithUnorderedAccompanyingPeriod() - { - $d = new \DateTime("2013/2/1"); + { + $d = new DateTime('2013/2/1'); $p = new Person($d); - - $e = new \DateTime("2013/3/1"); - $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); - $p->close($period); - - $f = new \DateTime("2013/1/1"); - $p->open(new AccompanyingPeriod($f)); - - $g = new \DateTime("2013/4/1"); - $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); - $p->close($period); - - $r = $p->getAccompanyingPeriodsOrdered(); - - $date = $r[0]->getOpeningDate()->format('Y-m-d'); - - $this->assertEquals($date, '2013-01-01'); - } - - /** - * Test if the getAccompanyingPeriodsOrdered function, for periods - * starting at the same time order regarding to the closing date. - */ - public function testAccompanyingPeriodOrderSameDateOpening() { - $d = new \DateTime("2013/2/1"); - $p = new Person($d); - - $g = new \DateTime("2013/4/1"); - $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); - $p->close($period); - - $f = new \DateTime("2013/2/1"); - $p->open(new AccompanyingPeriod($f)); - - $e = new \DateTime("2013/3/1"); + + $e = new DateTime('2013/3/1'); $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); $p->close($period); + $f = new DateTime('2013/1/1'); + $p->open(new AccompanyingPeriod($f)); + + $g = new DateTime('2013/4/1'); + $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); + $p->close($period); + $r = $p->getAccompanyingPeriodsOrdered(); - - $date = $r[0]->getClosingDate()->format('Y-m-d'); - - $this->assertEquals($date, '2013-03-01'); + + $date = $r[0]->getOpeningDate()->format('Y-m-d'); + + $this->assertEquals($date, '2013-01-01'); } - + /** * Test if the function checkAccompanyingPeriodIsNotCovering returns * the good constant when two periods are collapsing : a period - * is covering another one : start_1 < start_2 & end_2 < end_1 + * is covering another one : start_1 < start_2 & end_2 < end_1. */ - public function testDateCoveringWithCoveringAccompanyingPeriod() { - $d = new \DateTime("2013/2/1"); + public function testDateCoveringWithCoveringAccompanyingPeriod() + { + $d = new DateTime('2013/2/1'); $p = new Person($d); - - $e = new \DateTime("2013/3/1"); + + $e = new DateTime('2013/3/1'); $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); $p->close($period); - - $f = new \DateTime("2013/1/1"); + + $f = new DateTime('2013/1/1'); $p->open(new AccompanyingPeriod($f)); - - $g = new \DateTime("2013/4/1"); + + $g = new DateTime('2013/4/1'); $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($g); $p->close($period); - + $r = $p->checkAccompanyingPeriodsAreNotCollapsing(); - + $this->assertEquals($r['result'], Person::ERROR_PERIODS_ARE_COLLAPSING); } - - /** - * Test if the function checkAccompanyingPeriodIsNotCovering returns - * the good constant when two periods are collapsing : a period is open - * before an existing period - */ - public function testNotOpenAFileReOpenedLater() { - $d = new \DateTime("2013/2/1"); - $p = new Person($d); - - $e = new \DateTime("2013/3/1"); - $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); - $p->close($period); - - $f = new \DateTime("2013/1/1"); - $p->open(new AccompanyingPeriod($f)); - - $r = $p->checkAccompanyingPeriodsAreNotCollapsing(); - - $this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD); - } - public function dateProvider(): Generator + /** + * Test the creation of an accompanying, its closure and the access to + * the current accompaniying period via the getCurrentAccompanyingPeriod + * function. + */ + public function testGetCurrentAccompanyingPeriod() { - yield [(DateTime::createFromFormat('Y-m-d', '2021-01-05'))->settime(0, 0)]; - yield [(DateTime::createFromFormat('Y-m-d', '2021-02-05'))->settime(0, 0)]; - yield [(DateTime::createFromFormat('Y-m-d', '2021-03-05'))->settime(0, 0)]; + $d = new DateTime('yesterday'); + $p = new Person($d); + + $period = $p->getCurrentAccompanyingPeriod(); + + $this->assertInstanceOf('Chill\PersonBundle\Entity\AccompanyingPeriod', $period); + $this->assertTrue($period->isOpen()); + $this->assertEquals($d, $period->getOpeningDate()); + + //close and test + $period->setClosingDate(new DateTime('tomorrow')); + + $shouldBeNull = $p->getCurrentAccompanyingPeriod(); + $this->assertNull($shouldBeNull); } /** @@ -205,4 +178,25 @@ class PersonTest extends \PHPUnit\Framework\TestCase $this::assertEquals($address3, $p->getLastAddress($addressDate3)); } + /** + * Test if the function checkAccompanyingPeriodIsNotCovering returns + * the good constant when two periods are collapsing : a period is open + * before an existing period. + */ + public function testNotOpenAFileReOpenedLater() + { + $d = new DateTime('2013/2/1'); + $p = new Person($d); + + $e = new DateTime('2013/3/1'); + $period = $p->getCurrentAccompanyingPeriod()->setClosingDate($e); + $p->close($period); + + $f = new DateTime('2013/1/1'); + $p->open(new AccompanyingPeriod($f)); + + $r = $p->checkAccompanyingPeriodsAreNotCollapsing(); + + $this->assertEquals($r['result'], Person::ERROR_ADDIND_PERIOD_AFTER_AN_OPEN_PERIOD); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php index 690f873e7..d1c4579c4 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/AgeAggregatorTest.php @@ -1,76 +1,64 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Export\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; +use DateTime; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class AgeAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\PersonBundle\Export\Aggregator\AgeAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.person.export.aggregator_age'); + + $this->aggregator = $container->get('chill.person.export.aggregator_age'); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array( - 'date_age_calculation' => \DateTime::createFromFormat('Y-m-d','2016-06-16') - ) - ); - } - - public function getQueryBuilders() - { - if (static::$kernel === null) { - static::bootKernel(); - } - - $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - - return array( - $em->createQueryBuilder() - ->select('count(person.id)') - ->from('ChillPersonBundle:Person', 'person') - ); + return [ + [ + 'date_age_calculation' => DateTime::createFromFormat('Y-m-d', '2016-06-16'), + ], + ]; } + public function getQueryBuilders() + { + if (null === static::$kernel) { + static::bootKernel(); + } + + $em = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager'); + + return [ + $em->createQueryBuilder() + ->select('count(person.id)') + ->from('ChillPersonBundle:Person', 'person'), + ]; + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php index fd91305dd..dda7f5b11 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/GenderAggregatorTest.php @@ -1,72 +1,61 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Aggregator; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; - /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class GenderAggregatorTest extends AbstractAggregatorTest { /** - * * @var \Chill\PersonBundle\Export\Aggregator\GenderAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.person.export.aggregator_gender'); + + $this->aggregator = $container->get('chill.person.export.aggregator_gender'); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } - + public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(person.id)') - ->from('ChillPersonBundle:Person', 'person') - ); + ->from('ChillPersonBundle:Person', 'person'), + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregator.php b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregator.php index 522b8edcd..c5fd06000 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregator.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Aggregator/NationalityAggregator.php @@ -1,73 +1,63 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Aggregator; require_once '/home/julien/dev/chill-dev/vendor/chill-project/main/Test/Export/AbstractAggregatorTest.php'; use Chill\MainBundle\Test\Export\AbstractAggregatorTest; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class NationalityAggregator extends AbstractAggregatorTest { /** - * * @var \Chill\PersonBundle\Export\Aggregator\NationalityAggregator */ private $aggregator; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->aggregator = $container->get('chill.person.export.aggregator_nationality'); + + $this->aggregator = $container->get('chill.person.export.aggregator_nationality'); } - + public function getAggregator() { return $this->aggregator; } - + public function getFormData() { - return array( - array('group_by_level' => 'country'), - array('group_by_level' => 'continent') - ); + return [ + ['group_by_level' => 'country'], + ['group_by_level' => 'continent'], + ]; } - + public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('count(person.id)') - ->from('ChillPersonBundle:Person', 'person') - ); + ->from('ChillPersonBundle:Person', 'person'), + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php index 5bb11f59a..35a1e0b5b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/CountPersonTest.php @@ -1,48 +1,39 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; /** - * Test CountPerson export + * Test CountPerson export. * - * @author julien.fastre@champs-libres.coop + * @internal + * @coversNothing */ class CountPersonTest extends AbstractExportTest { /** - * - * @var + * @var */ private $export; - + public function setUp() { static::bootKernel(); - + /* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ $container = self::$kernel->getContainer(); - + $this->export = $container->get('chill.person.export.export_count_person'); } - - + public function getExport() { return $this->export; @@ -50,13 +41,13 @@ class CountPersonTest extends AbstractExportTest public function getFormData() { - return array( - array() - ); + return [ + [], + ]; } public function getModifiersCombination() { - return array( [ 'person' ] ); + return [['person']]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php index 44ab79f96..d853254e0 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Export/ListPersonTest.php @@ -1,64 +1,50 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Export\Export; use Chill\MainBundle\Test\Export\AbstractExportTest; use Chill\PersonBundle\Export\Export\ListPerson; - +use DateTime; /** - * Test the export "ListPerson" + * Test the export "ListPerson". * - * @author julien.fastre@champs-libres.coop + * @internal + * @coversNothing */ class ListPersonTest extends AbstractExportTest { /** - * - * @var ListPerson + * @var ListPerson */ private $export; - - + public function setUp() { - static::bootKernel(); - + static::bootKernel(); + /* @var $container \Symfony\Component\DependencyInjection\ContainerInterface */ $container = self::$kernel->getContainer(); - + $this->export = $container->get('chill.person.export.list_person'); - + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container->get('request_stack') - ->push($request->reveal()); + ->push($request->reveal()); } - - /** - * - * {@inheritDoc} - */ + public function getExport() { return $this->export; @@ -66,26 +52,24 @@ class ListPersonTest extends AbstractExportTest public function getFormData() { - return array( - array('fields' => ['id', 'firstName', 'lastName']), - array('fields' => ['id', 'birthdate', 'gender', 'memo', 'email', 'phonenumber']), - array('fields' => ['firstName', 'lastName', 'phonenumber']), - array('fields' => ['id', 'nationality']), - array('fields' => ['id', 'countryOfBirth']), - array('fields' => ['id', 'address_street_address_1', - 'address_street_address_2', 'address_valid_from', - 'address_postcode_label', 'address_postcode_code', - 'address_country_name', 'address_country_code'], - 'address_date' => \DateTime::createFromFormat('Y-m-d', '2016-06-12')) - ); + return [ + ['fields' => ['id', 'firstName', 'lastName']], + ['fields' => ['id', 'birthdate', 'gender', 'memo', 'email', 'phonenumber']], + ['fields' => ['firstName', 'lastName', 'phonenumber']], + ['fields' => ['id', 'nationality']], + ['fields' => ['id', 'countryOfBirth']], + ['fields' => ['id', 'address_street_address_1', + 'address_street_address_2', 'address_valid_from', + 'address_postcode_label', 'address_postcode_code', + 'address_country_name', 'address_country_code', ], + 'address_date' => DateTime::createFromFormat('Y-m-d', '2016-06-12'), ], + ]; } - + public function getModifiersCombination() { - return array( - array('person') - ); + return [ + ['person'], + ]; } - - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php index a0f4ed1be..3a87c21aa 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/AccompanyingPeriodFilterTest.php @@ -1,51 +1,42 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Filter; use Chill\MainBundle\Test\Export\AbstractFilterTest; +use DateTime; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; /** - * - * + * @internal + * @coversNothing */ class AccompanyingPeriodFilterTest extends AbstractFilterTest { /** - * * @var \Chill\PersonBundle\Export\Filter\BirthdateFilter */ private $filter; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - + try { $this->filter = $container->get('chill.person.export.filter_accompanying_period'); - } catch (ServiceNotFoundException $e) { - $this->markTestSkipped("The current configuration does not use accompanying_periods"); + } catch (ServiceNotFoundException $e) { + $this->markTestSkipped('The current configuration does not use accompanying_periods'); } } - - + public function getFilter() { return $this->filter; @@ -53,24 +44,24 @@ class AccompanyingPeriodFilterTest extends AbstractFilterTest public function getFormData() { - return array( - array( - 'date_from' => \DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => \DateTime::createFromFormat('Y-m-d', '2010-01-01') - ) - ); + return [ + [ + 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), + 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), + ], + ]; } public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('person.firstName') ->from('ChillPersonBundle:Person', 'person'), @@ -93,9 +84,9 @@ class AccompanyingPeriodFilterTest extends AbstractFilterTest $em->createQueryBuilder() ->select('activity.date AS date') ->select('activity.attendee as attendee') - ->from("ChillActivityBundle:Activity", 'activity') + ->from('ChillActivityBundle:Activity', 'activity') ->join('activity.person', 'person') - ->join('person.center', 'center') - ); + ->join('person.center', 'center'), + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php index 1bcb040e4..0e105fd60 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/BirthdayFilterTest.php @@ -1,47 +1,37 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Filter; use Chill\MainBundle\Test\Export\AbstractFilterTest; +use DateTime; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class BirthdayFilterTest extends AbstractFilterTest { /** - * * @var \Chill\PersonBundle\Export\Filter\BirthdateFilter */ private $filter; - + public function setUp() { static::bootKernel(); - + $container = static::$kernel->getContainer(); - - $this->filter = $container->get('chill.person.export.filter_birthdate'); + + $this->filter = $container->get('chill.person.export.filter_birthdate'); } - - + public function getFilter() { return $this->filter; @@ -49,24 +39,24 @@ class BirthdayFilterTest extends AbstractFilterTest public function getFormData() { - return array( - array( - 'date_from' => \DateTime::createFromFormat('Y-m-d', '2000-01-01'), - 'date_to' => \DateTime::createFromFormat('Y-m-d', '2010-01-01') - ) - ); + return [ + [ + 'date_from' => DateTime::createFromFormat('Y-m-d', '2000-01-01'), + 'date_to' => DateTime::createFromFormat('Y-m-d', '2010-01-01'), + ], + ]; } public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('p.firstName') ->from('ChillPersonBundle:Person', 'p'), @@ -79,7 +69,7 @@ class BirthdayFilterTest extends AbstractFilterTest ->select('count(IDENTITY(p))') ->from('ChillPersonBundle:Person', 'p') // add a dummy where clause - ->where('p.firstname IS NOT NULL') - ); + ->where('p.firstname IS NOT NULL'), + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php index dce198344..e71f0225f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Export/Filter/GenderFilterTest.php @@ -1,54 +1,43 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\PersonBundle\Tests\Export\Filter; use Chill\MainBundle\Test\Export\AbstractFilterTest; use Chill\PersonBundle\Entity\Person; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class GenderFilterTest extends AbstractFilterTest { /** - * * @var \Chill\PersonBundle\Export\Filter\GenderFilter */ private $filter; - + public function setUp() { static::bootKernel(); - + // add a fake request with a default locale (used in translatable string) - $prophet = new \Prophecy\Prophet; + $prophet = new \Prophecy\Prophet(); $request = $prophet->prophesize(); $request->willExtend(\Symfony\Component\HttpFoundation\Request::class); $request->getLocale()->willReturn('fr'); - + $container = static::$kernel->getContainer(); - - $this->filter = $container->get('chill.person.export.filter_gender'); + + $this->filter = $container->get('chill.person.export.filter_gender'); } - - + public function getFilter() { return $this->filter; @@ -56,32 +45,32 @@ class GenderFilterTest extends AbstractFilterTest public function getFormData() { - return array( - array( - 'accepted_genders' => [ Person::FEMALE_GENDER ] - ), - array( - 'accepted_genders' => [ Person::MALE_GENDER ] - ), - array( - 'accepted_genders' => [ Person::MALE_GENDER, Person::BOTH_GENDER ] - ) - ); + return [ + [ + 'accepted_genders' => [Person::FEMALE_GENDER], + ], + [ + 'accepted_genders' => [Person::MALE_GENDER], + ], + [ + 'accepted_genders' => [Person::MALE_GENDER, Person::BOTH_GENDER], + ], + ]; } public function getQueryBuilders() { - if (static::$kernel === null) { + if (null === static::$kernel) { static::bootKernel(); } - + $em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); - - return array( + + return [ $em->createQueryBuilder() ->select('p.firstName') - ->from('ChillPersonBundle:Person', 'p') - ); + ->from('ChillPersonBundle:Person', 'p'), + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php b/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php index cb796b742..2e55a4d22 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Form/Type/PickPersonTypeTest.php @@ -1,173 +1,165 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Form\Type; +use Chill\PersonBundle\Form\Type\PickPersonType; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Chill\PersonBundle\Form\Type\PickPersonType; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class PickPersonTypeTest extends KernelTestCase { /** - * - * @var \Chill\MainBundle\Entity\User - */ - protected $user; - - /** - * * @var \Symfony\Component\Form\FormFactoryInterface */ protected $formFactory; - + + /** + * @var \Chill\MainBundle\Entity\User + */ + protected $user; + public function setUp() { self::bootKernel(); - + $this->user = self::$container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => 'multi_center')); - + ->getRepository('ChillMainBundle:User') + ->findOneBy(['username' => 'multi_center']); + $this->formFactory = self::$container->get('form.factory'); - + $token = (new UsernamePasswordToken($this->user, 'password', 'firewall')); self::$container->get('security.token_storage') - ->setToken($token); + ->setToken($token); } - - public function testWithoutOption() - { - $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array()) - ->getForm(); - - $this->assertInstanceOf(\Symfony\Component\Form\FormInterface::class, - $form); - - // transform into a view to have data-center attr - $view = $form->createView(); - - $centerIds = array(); - - /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ - foreach($view->vars['choices'] as $choice) { - $centerIds[] = $choice->attr['data-center']; - } - - $this->assertEquals(2, count(array_unique($centerIds)), - "test that the form contains people from 2 centers"); - } - + /** - * Test the form with an option 'centers' with an unique center - * entity (not in an array) - */ - public function testWithOptionCenter() - { - $center = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')) - ; - - $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'centers' => $center - )) - ->getForm(); - - // transform into a view to have data-center attr - $view = $form->createView(); - - /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ - foreach($view->vars['choices'] as $choice) { - $centerIds[] = $choice->attr['data-center']; - } - - $this->assertEquals(1, count(array_unique($centerIds)), - "test that the form contains people from only one centers"); - - $this->assertEquals($center->getId(), array_unique($centerIds)[0]); - - } - - /** - * Test the form with multiple centers - */ - public function testWithOptionCenters() - { - $centers = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:Center') - ->findAll() - ; - - $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'centers' => $centers - )) - ->getForm(); - - // transform into a view to have data-center attr - $view = $form->createView(); - - /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ - foreach($view->vars['choices'] as $choice) { - $centerIds[] = $choice->attr['data-center']; - } - - $this->assertEquals(2, count(array_unique($centerIds)), - "test that the form contains people from only one centers"); - - } - - /** - * test with an invalid center type in the option 'centers' (in an array) - * + * test with an invalid center type in the option 'centers' (in an array). + * * @expectedException \RuntimeException */ public function testWithInvalidOptionCenters() { - $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'centers' => array('string') - )) - ->getForm(); + ->createBuilder(PickPersonType::class, null, [ + 'centers' => ['string'], + ]) + ->getForm(); } - + + /** + * Test the form with an option 'centers' with an unique center + * entity (not in an array). + */ + public function testWithOptionCenter() + { + $center = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:Center') + ->findOneBy(['name' => 'Center A']); + + $form = $this->formFactory + ->createBuilder(PickPersonType::class, null, [ + 'centers' => $center, + ]) + ->getForm(); + + // transform into a view to have data-center attr + $view = $form->createView(); + + /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ + foreach ($view->vars['choices'] as $choice) { + $centerIds[] = $choice->attr['data-center']; + } + + $this->assertEquals( + 1, + count(array_unique($centerIds)), + 'test that the form contains people from only one centers' + ); + + $this->assertEquals($center->getId(), array_unique($centerIds)[0]); + } + + /** + * Test the form with multiple centers. + */ + public function testWithOptionCenters() + { + $centers = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:Center') + ->findAll(); + + $form = $this->formFactory + ->createBuilder(PickPersonType::class, null, [ + 'centers' => $centers, + ]) + ->getForm(); + + // transform into a view to have data-center attr + $view = $form->createView(); + + /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ + foreach ($view->vars['choices'] as $choice) { + $centerIds[] = $choice->attr['data-center']; + } + + $this->assertEquals( + 2, + count(array_unique($centerIds)), + 'test that the form contains people from only one centers' + ); + } + public function testWithOptionRoleInvalid() { $form = $this->formFactory - ->createBuilder(PickPersonType::class, null, array( - 'role' => new \Symfony\Component\Security\Core\Role\Role('INVALID') - )) - ->getForm(); - + ->createBuilder(PickPersonType::class, null, [ + 'role' => new \Symfony\Component\Security\Core\Role\Role('INVALID'), + ]) + ->getForm(); + // transform into a view to have data-center attr $view = $form->createView(); - + $this->assertEquals(0, count($view->vars['choices'])); } - + + public function testWithoutOption() + { + $form = $this->formFactory + ->createBuilder(PickPersonType::class, null, []) + ->getForm(); + + $this->assertInstanceOf( + \Symfony\Component\Form\FormInterface::class, + $form + ); + + // transform into a view to have data-center attr + $view = $form->createView(); + + $centerIds = []; + + /* @var $centerIds \Symfony\Component\Form\ChoiceList\View\ChoiceView */ + foreach ($view->vars['choices'] as $choice) { + $centerIds[] = $choice->attr['data-center']; + } + + $this->assertEquals( + 2, + count(array_unique($centerIds)), + 'test that the form contains people from 2 centers' + ); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php b/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php index b2c94b6bc..b563a8257 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Search/PersonSearchTest.php @@ -1,237 +1,231 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Search; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; - /** - * Test Person search + * Test Person search. * - * @author Julien Fastré + * @internal + * @coversNothing */ class PersonSearchTest extends WebTestCase { + public function testDefaultAccented() + { + $crawlerSpecial = $this->generateCrawlerForSearch('@person manço'); + + $this->assertRegExp('/Manço/', $crawlerSpecial->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco'); + + $this->assertRegExp('/Manço/', $crawlerNoSpecial->text()); + + $crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne'); + + $this->assertRegExp('/Étienne/', $crawlerSpecial->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person etienne'); + + $this->assertRegExp('/Étienne/', $crawlerNoSpecial->text()); + } + public function testExpected() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@person Depardieu' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@person Depardieu', + ]); + $this->assertRegExp('/Depardieu/', $crawler->text()); } - + public function testExpectedNamed() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@person Depardieu', 'name' => 'person_regular' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@person Depardieu', 'name' => 'person_regular', + ]); + $this->assertRegExp('/Depardieu/', $crawler->text()); } - - public function testSearchByFirstName() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - - public function testSearchByFirstNameLower() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:depardieu'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - - public function testSearchByFirstNamePartim() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Dep'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - + public function testFirstNameAccentued() { $crawlerSpecial = $this->generateCrawlerForSearch('@person firstname:manço'); - + $this->assertRegExp('/Manço/', $crawlerSpecial->text()); - - + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person firstname:manco'); - + $this->assertRegExp('/Manço/', $crawlerNoSpecial->text()); } - - public function testSearchByLastName() - { - $crawler = $this->generateCrawlerForSearch('@person lastname:Jean'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - - public function testSearchByLastNameLower() - { - $crawler = $this->generateCrawlerForSearch('@person lastname:jean'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - - public function testSearchByLastNamePartim() - { - $crawler = $this->generateCrawlerForSearch('@person lastname:ean'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - } - - public function testSearchByLastNameAccented() - { - $crawlerSpecial = $this->generateCrawlerForSearch('@person lastname:Gérard'); - - $this->assertRegExp('/Gérard/', $crawlerSpecial->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person lastname:Gerard'); - - $this->assertRegExp('/Gérard/', $crawlerNoSpecial->text()); - } - - public function testSearchCombineFirstnameAndNationality() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu nationality:RU'); - - $this->assertRegExp('/Gérard/', $crawler->text()); - //if this is a AND clause, Jean Depardieu should not appears - $this->assertNotRegExp('/Jean/', $crawler->text(), - "assert clause firstname and nationality are AND"); - } - - public function testSearchCombineLastnameAndFirstName() - { - $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu lastname:Jean'); - - $this->assertRegExp('/Depardieu/', $crawler->text()); - //if this is a AND clause, Jean Depardieu should not appears - $this->assertNotRegExp('/Gérard/', $crawler->text(), - "assert clause firstname and nationality are AND"); - } - + public function testSearchBirthdate() { $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27'); - + $this->assertRegExp('/Gérard/', $crawler->text()); $this->assertRegExp('/Bart/', $crawler->text()); } - + + public function testSearchByFirstName() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + + public function testSearchByFirstNameLower() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:depardieu'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + + public function testSearchByFirstNamePartim() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Dep'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + + public function testSearchByLastName() + { + $crawler = $this->generateCrawlerForSearch('@person lastname:Jean'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + + public function testSearchByLastNameAccented() + { + $crawlerSpecial = $this->generateCrawlerForSearch('@person lastname:Gérard'); + + $this->assertRegExp('/Gérard/', $crawlerSpecial->text()); + + $crawlerNoSpecial = $this->generateCrawlerForSearch('@person lastname:Gerard'); + + $this->assertRegExp('/Gérard/', $crawlerNoSpecial->text()); + } + + public function testSearchByLastNameLower() + { + $crawler = $this->generateCrawlerForSearch('@person lastname:jean'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + + public function testSearchByLastNamePartim() + { + $crawler = $this->generateCrawlerForSearch('@person lastname:ean'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + } + public function testSearchCombineBirthdateAndFirstName() { $crawler = $this->generateCrawlerForSearch('@person birthdate:1948-12-27 firstname:(Van Snick)'); - + $this->assertRegExp('/Bart/', $crawler->text()); $this->assertNotRegExp('/Depardieu/', $crawler->text()); } - + + public function testSearchCombineFirstnameAndNationality() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu nationality:RU'); + + $this->assertRegExp('/Gérard/', $crawler->text()); + //if this is a AND clause, Jean Depardieu should not appears + $this->assertNotRegExp( + '/Jean/', + $crawler->text(), + 'assert clause firstname and nationality are AND' + ); + } + public function testSearchCombineGenderAndFirstName() { $crawler = $this->generateCrawlerForSearch('@person gender:woman firstname:(Depardieu)'); - + $this->assertRegExp('/Charline/', $crawler->text()); $this->assertNotRegExp('/Gérard/', $crawler->text()); } - + + public function testSearchCombineLastnameAndFirstName() + { + $crawler = $this->generateCrawlerForSearch('@person firstname:Depardieu lastname:Jean'); + + $this->assertRegExp('/Depardieu/', $crawler->text()); + //if this is a AND clause, Jean Depardieu should not appears + $this->assertNotRegExp( + '/Gérard/', + $crawler->text(), + 'assert clause firstname and nationality are AND' + ); + } + public function testSearchMultipleTrigramUseAndClauseInDefault() { $crawler = $this->generateCrawlerForSearch('@person cha dep'); - + $this->assertRegExp('/Charline/', $crawler->text()); $this->assertNotRegExp('/Gérard/', $crawler->text()); $this->assertNotRegExp('/Jean/', $crawler->text()); } - - - - public function testDefaultAccented() - { - $crawlerSpecial = $this->generateCrawlerForSearch('@person manço'); - - $this->assertRegExp('/Manço/', $crawlerSpecial->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person manco'); - - $this->assertRegExp('/Manço/', $crawlerNoSpecial->text()); - - $crawlerSpecial = $this->generateCrawlerForSearch('@person Étienne'); - - $this->assertRegExp('/Étienne/', $crawlerSpecial->text()); - - - $crawlerNoSpecial = $this->generateCrawlerForSearch('@person etienne'); - - $this->assertRegExp('/Étienne/', $crawlerNoSpecial->text()); - } - + /** - * test that person which a user cannot see are not displayed in results + * test that person which a user cannot see are not displayed in results. */ public function testSearchWithAuthorization() { $crawlerCanSee = $this->generateCrawlerForSearch('Gérard', 'center a_social'); $crawlerCannotSee = $this->generateCrawlerForSearch('Gérard', 'center b_social'); - - $this->assertRegExp('/Gérard/', $crawlerCanSee->text(), - 'center a_social may see "Gérard" in center a'); - $this->assertRegExp('/Aucune personne ne correspond aux termes de recherche/', - $crawlerCannotSee->text(), - 'center b_social may not see any "Gérard" associated to center b'); - + + $this->assertRegExp( + '/Gérard/', + $crawlerCanSee->text(), + 'center a_social may see "Gérard" in center a' + ); + $this->assertRegExp( + '/Aucune personne ne correspond aux termes de recherche/', + $crawlerCannotSee->text(), + 'center b_social may not see any "Gérard" associated to center b' + ); } - + private function generateCrawlerForSearch($pattern, $username = 'center a_social') { $client = $this->getAuthenticatedClient($username); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => $pattern - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => $pattern, + ]); + $this->assertTrue($client->getResponse()->isSuccessful()); - + return $crawler; } - + /** - * + * @param mixed $username + * * @return \Symfony\Component\BrowserKit\Client */ private function getAuthenticatedClient($username = 'center a_social') { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => 'password', - )); + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => 'password', + ]); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Security/Authorization/PersonVoterTest.php b/src/Bundle/ChillPersonBundle/Tests/Security/Authorization/PersonVoterTest.php index 474fbc103..666865aaf 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Security/Authorization/PersonVoterTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Security/Authorization/PersonVoterTest.php @@ -1,184 +1,167 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Security\Authorization; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; -use Chill\PersonBundle\Entity\Person; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\PermissionsGroup; -use Chill\MainBundle\Entity\GroupCenter; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\Entity\Scope; -use Chill\MainBundle\Test\PrepareUserTrait; use Chill\MainBundle\Test\PrepareCenterTrait; use Chill\MainBundle\Test\PrepareScopeTrait; -use Chill\MainBundle\Test\ProphecyTrait; +use Chill\MainBundle\Test\PrepareUserTrait; +use Chill\PersonBundle\Entity\Person; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; /** - * Test PersonVoter + * Test PersonVoter. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class PersonVoterTest extends KernelTestCase { - - use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait; - + use PrepareCenterTrait; + use PrepareScopeTrait; + use PrepareUserTrait; + /** - * - * @var \Chill\PersonBundle\Security\Authorization\PersonVoter - */ - protected $voter; - - /** - * * @var \Prophecy\Prophet */ protected $prophet; - + + /** + * @var \Chill\PersonBundle\Security\Authorization\PersonVoter + */ + protected $voter; + public function setUp() { static::bootKernel(); $this->voter = static::$kernel->getContainer() - ->get('chill.person.security.authorization.person'); + ->get('chill.person.security.authorization.person'); $this->prophet = new \Prophecy\Prophet(); } - + public function testNullUser() { $token = $this->prepareToken(); $center = $this->prepareCenter(1, 'center'); $person = $this->preparePerson($center); - + $this->assertEquals( - VoterInterface::ACCESS_DENIED, - $this->voter->vote($token, $person, array('CHILL_PERSON_SEE')), - "assert that a null user is not allowed to see" - ); + VoterInterface::ACCESS_DENIED, + $this->voter->vote($token, $person, ['CHILL_PERSON_SEE']), + 'assert that a null user is not allowed to see' + ); } - - public function testUserCanNotReachCenter() - { - $centerA = $this->prepareCenter(1, 'centera'); - $centerB = $this->prepareCenter(2, 'centerb'); - $scope = $this->prepareScope(1, 'default'); - $token = $this->prepareToken(array( - array( - 'center' => $centerA, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_PERSON_UPDATE'] - ) - ) - )); - $person = $this->preparePerson($centerB); - - $this->assertEquals( - VoterInterface::ACCESS_DENIED, - $this->voter->vote($token, $person, array('CHILL_PERSON_UPDATE')), - 'assert that a user with right not in the good center has access denied' - ); - } - + /** - * test a user with sufficient right may see the person + * test a user with sufficient right may see the person. */ public function testUserAllowed() { $center = $this->prepareCenter(1, 'center'); $scope = $this->prepareScope(1, 'default'); - $token = $this->prepareToken(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_PERSON_SEE'] - ) - ) - )); + $token = $this->prepareToken([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_PERSON_SEE'], + ], + ], + ]); $person = $this->preparePerson($center); - + $this->assertEquals( - VoterInterface::ACCESS_GRANTED, - $this->voter->vote($token, $person, array('CHILL_PERSON_SEE')), - 'assert that a user with correct rights may is granted access' - ); + VoterInterface::ACCESS_GRANTED, + $this->voter->vote($token, $person, ['CHILL_PERSON_SEE']), + 'assert that a user with correct rights may is granted access' + ); } - + /** * test a user with sufficient right may see the person. - * hierarchy between role is required + * hierarchy between role is required. */ public function testUserAllowedWithInheritance() { $center = $this->prepareCenter(1, 'center'); $scope = $this->prepareScope(1, 'default'); - $token = $this->prepareToken(array( - array( - 'center' => $center, 'permissionsGroup' => array( - ['scope' => $scope, 'role' => 'CHILL_PERSON_UPDATE'] - ) - ) - )); + $token = $this->prepareToken([ + [ + 'center' => $center, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_PERSON_UPDATE'], + ], + ], + ]); $person = $this->preparePerson($center); $this->assertEquals( - VoterInterface::ACCESS_GRANTED, - $this->voter->vote($token, $person, array('CHILL_PERSON_SEE')), - 'assert that a user with correct role is granted on inherited roles' - ); - } - + VoterInterface::ACCESS_GRANTED, + $this->voter->vote($token, $person, ['CHILL_PERSON_SEE']), + 'assert that a user with correct role is granted on inherited roles' + ); + } + + public function testUserCanNotReachCenter() + { + $centerA = $this->prepareCenter(1, 'centera'); + $centerB = $this->prepareCenter(2, 'centerb'); + $scope = $this->prepareScope(1, 'default'); + $token = $this->prepareToken([ + [ + 'center' => $centerA, 'permissionsGroup' => [ + ['scope' => $scope, 'role' => 'CHILL_PERSON_UPDATE'], + ], + ], + ]); + $person = $this->preparePerson($centerB); + + $this->assertEquals( + VoterInterface::ACCESS_DENIED, + $this->voter->vote($token, $person, ['CHILL_PERSON_UPDATE']), + 'assert that a user with right not in the good center has access denied' + ); + } + /** - * prepare a person - * + * prepare a person. + * * The only properties set is the center, others properties are ignored. - * - * @param Center $center + * * @return Person */ protected function preparePerson(Center $center) { return (new Person()) - ->setCenter($center) - ; + ->setCenter($center); } - + /** - * prepare a token interface with correct rights - * + * prepare a token interface with correct rights. + * * if $permissions = null, user will be null (no user associated with token - * + * * @param array $permissions an array of permissions, with key 'center' for the center and 'permissions' for an array of permissions + * * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface */ - protected function prepareToken(array $permissions = null) - { + protected function prepareToken(?array $permissions = null) + { $token = $this->prophet->prophesize(); $token ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - if ($permissions === NULL) { + + if (null === $permissions) { $token->getUser()->willReturn(null); } else { $token->getUser()->willReturn($this->prepareUser($permissions)); } - + return $token->reveal(); } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php b/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php index 9d3e6ccd8..09823d52d 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Timeline/TimelineAccompanyingPeriodTest.php @@ -1,61 +1,54 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Timeline; -use Symfony\Bundle\SecurityBundle\Tests\Functional\WebTestCase; -use Chill\PersonBundle\Entity\Person; -use Chill\PersonBundle\Entity\AccompanyingPeriod; - /** - * This class tests entries are shown for closing and opening + * This class tests entries are shown for closing and opening * periods in timeline. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class TimelineAccompanyingPeriodTest extends \Chill\PersonBundle\Tests\Controller\AccompanyingPeriodControllerTest { - public function testEntriesAreShown() + public function testEntriesAreShown() { - $this->generatePeriods(array( + $this->generatePeriods([ [ 'openingDate' => '2014-01-01', 'closingDate' => '2014-12-31', - 'closingMotive' => $this->getRandomClosingMotive() - ] - )); - + 'closingMotive' => $this->getRandomClosingMotive(), + ], + ]); + $crawler = $this->client->request('GET', '/en/person/' - .$this->person->getId().'/timeline'); - - $this->assertTrue($this->client->getResponse()->isSuccessful(), - "the timeline page loads sucessfully"); - $this->assertGreaterThan(0, $crawler->filter('.timeline div')->count(), - "the timeline page contains multiple div inside a .timeline element"); - $this->assertContains("Ouverture d'une période d'accompagnement", - $crawler->filter('.timeline')->text(), - "the text 'une période d'accompagnement a été ouverte' is present"); - $this->assertContains("Fermeture de la période d'accompagnement", - $crawler->Filter('.timeline')->text(), - "the text 'Une période d'accompagnement a été fermée' is present"); + . $this->person->getId() . '/timeline'); + + $this->assertTrue( + $this->client->getResponse()->isSuccessful(), + 'the timeline page loads sucessfully' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.timeline div')->count(), + 'the timeline page contains multiple div inside a .timeline element' + ); + $this->assertContains( + "Ouverture d'une période d'accompagnement", + $crawler->filter('.timeline')->text(), + "the text 'une période d'accompagnement a été ouverte' is present" + ); + $this->assertContains( + "Fermeture de la période d'accompagnement", + $crawler->Filter('.timeline')->text(), + "the text 'Une période d'accompagnement a été fermée' is present" + ); } - } diff --git a/src/Bundle/ChillPersonBundle/Tests/Validator/BirthdateValidatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Validator/BirthdateValidatorTest.php index 57b4c2577..462830b6b 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Validator/BirthdateValidatorTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Validator/BirthdateValidatorTest.php @@ -1,112 +1,101 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Tests\Validator; -use Chill\PersonBundle\Validator\Constraints\BirthdateValidator; use Chill\PersonBundle\Validator\Constraints\Birthdate; +use Chill\PersonBundle\Validator\Constraints\BirthdateValidator; +use DateInterval; +use DateTime; use Prophecy\Argument; use Prophecy\Prophet; /** - * Test the behaviour of BirthdayValidator + * Test the behaviour of BirthdayValidator. * - * @author Julien Fastré + * @internal + * @coversNothing */ class BirthdateValidatorTest extends \PHPUnit\Framework\TestCase { /** - * A prophecy for \Symfony\Component\Validator\Context\ExecutionContextInterface + * @var Birthdate + */ + private $constraint; + + /** + * A prophecy for \Symfony\Component\Validator\Context\ExecutionContextInterface. * * Will reveal \Symfony\Component\Validator\Context\ExecutionContextInterface */ private $context; - + private $prophet; - - /** - * - * @var Birthdate - */ - private $constraint; - + public function setUp() { - $this->prophet = new Prophet; - + $this->prophet = new Prophet(); + $constraintViolationBuilder = $this->prophet->prophesize(); $constraintViolationBuilder->willImplement('Symfony\Component\Validator\Violation\ConstraintViolationBuilderInterface'); $constraintViolationBuilder->setParameter(Argument::any(), Argument::any()) - ->willReturn($constraintViolationBuilder->reveal()); + ->willReturn($constraintViolationBuilder->reveal()); $constraintViolationBuilder->addViolation() - ->willReturn($constraintViolationBuilder->reveal()); - + ->willReturn($constraintViolationBuilder->reveal()); + $this->context = $this->prophet->prophesize(); $this->context->willImplement('Symfony\Component\Validator\Context\ExecutionContextInterface'); $this->context->buildViolation(Argument::type('string')) - ->willReturn($constraintViolationBuilder->reveal()); - + ->willReturn($constraintViolationBuilder->reveal()); + $this->constraint = new Birthdate(); } - - public function testValidBirthDate() - { - - $date = new \DateTime('2015-01-01'); - - $birthdateValidator = new BirthdateValidator(); - $birthdateValidator->initialize($this->context->reveal()); - - $birthdateValidator->validate($date, $this->constraint); - - $this->context->buildViolation(Argument::any())->shouldNotHaveBeenCalled(); - } - - public function testInvalidBirthDate() - { - $date = new \DateTime('tomorrow'); - - $birthdateValidator = new BirthdateValidator(); - $birthdateValidator->initialize($this->context->reveal()); - - $birthdateValidator->validate($date, $this->constraint); - - $this->context->buildViolation(Argument::type('string'))->shouldHaveBeenCalled(); - } - - public function testInvalidBirthDateWithParameter() - { - $date = (new \DateTime('today'))->sub(new \DateInterval('P1M')); - - $birthdateValidator = new BirthdateValidator('P1Y'); - $birthdateValidator->initialize($this->context->reveal()); - - $birthdateValidator->validate($date, $this->constraint); - - $this->context->buildViolation(Argument::type('string'))->shouldHaveBeenCalled(); - } - + public function tearDown() { $this->prophet->checkPredictions(); } - - + + public function testInvalidBirthDate() + { + $date = new DateTime('tomorrow'); + + $birthdateValidator = new BirthdateValidator(); + $birthdateValidator->initialize($this->context->reveal()); + + $birthdateValidator->validate($date, $this->constraint); + + $this->context->buildViolation(Argument::type('string'))->shouldHaveBeenCalled(); + } + + public function testInvalidBirthDateWithParameter() + { + $date = (new DateTime('today'))->sub(new DateInterval('P1M')); + + $birthdateValidator = new BirthdateValidator('P1Y'); + $birthdateValidator->initialize($this->context->reveal()); + + $birthdateValidator->validate($date, $this->constraint); + + $this->context->buildViolation(Argument::type('string'))->shouldHaveBeenCalled(); + } + + public function testValidBirthDate() + { + $date = new DateTime('2015-01-01'); + + $birthdateValidator = new BirthdateValidator(); + $birthdateValidator->initialize($this->context->reveal()); + + $birthdateValidator->validate($date, $this->constraint); + + $this->context->buildViolation(Argument::any())->shouldNotHaveBeenCalled(); + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/bootstrap.php b/src/Bundle/ChillPersonBundle/Tests/bootstrap.php index 9211155e5..0eb126c4f 100644 --- a/src/Bundle/ChillPersonBundle/Tests/bootstrap.php +++ b/src/Bundle/ChillPersonBundle/Tests/bootstrap.php @@ -1,8 +1,14 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Timeline; use Chill\MainBundle\Timeline\TimelineProviderInterface; use Doctrine\ORM\EntityManager; +use LogicException; /** - * Provide method to build timeline for accompanying periods - * + * Provide method to build timeline for accompanying periods. + * * This class is resued by TimelineAccompanyingPeriodOpening (for opening) * and TimelineAccompanyingPeriodClosing (for closing) - * - * @author Julien Fastré */ abstract class AbstractTimelineAccompanyingPeriod implements TimelineProviderInterface { /** - * * @var EntityManager */ protected $em; - + public function __construct(EntityManager $em) { $this->em = $em; } - /** - * - * {@inheritDoc} - */ public function getEntities(array $ids) { $periods = $this->em - ->getRepository('ChillPersonBundle:AccompanyingPeriod') - ->findBy(array('id' => $ids)); - + ->getRepository('ChillPersonBundle:AccompanyingPeriod') + ->findBy(['id' => $ids]); + //set results in an associative array with id as indexes - $results = array(); - foreach($periods as $period) { + $results = []; + + foreach ($periods as $period) { $results[$period->getId()] = $period; } - + return $results; } /** - * prepare fetchQuery without `WHERE` and `TYPE` clause - * + * prepare fetchQuery without `WHERE` and `TYPE` clause. + * * @param string $context - * @param array $args + * + * @throws LogicException + * * @return array - * @throws \LogicException */ protected function basicFetchQuery($context, array $args) { - if ($context !== 'person') { - throw new \LogicException('TimelineAccompanyingPeriod is not able ' - . 'to render context '.$context); + if ('person' !== $context) { + throw new LogicException('TimelineAccompanyingPeriod is not able ' + . 'to render context ' . $context); } - + $metadata = $this->em - ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod') - ; - - return array( + ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod'); + + return [ 'id' => $metadata->getColumnName('id'), 'FROM' => $metadata->getTableName(), - 'WHERE' => sprintf('%s = %d', + 'WHERE' => sprintf( + '%s = %d', $metadata ->getAssociationMapping('person')['joinColumns'][0]['name'], - $args['person']->getId()) - ); + $args['person']->getId() + ), + ]; } /** - * return the expected response for TimelineProviderInterface::getEntityTemplate - * + * return the expected response for TimelineProviderInterface::getEntityTemplate. + * * @param string $template the template for rendering * @param mixed $entity * @param string $context - * @param array $args + * * @return array */ protected function getBasicEntityTemplate($template, $entity, $context, array $args) { - return array( + return [ 'template' => $template, - 'template_data' => ['person' => $args['person'], 'period' => $entity] - ); + 'template_data' => ['person' => $args['person'], 'period' => $entity], + ]; } } diff --git a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php index 05aebbfd4..981cbe9fa 100644 --- a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php +++ b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodClosing.php @@ -1,78 +1,51 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; - /** - * Provide information for opening periods to timeline - * - * @author Julien Fastré + * Provide information for opening periods to timeline. */ class TimelineAccompanyingPeriodClosing extends AbstractTimelineAccompanyingPeriod { - - /** - * - * {@inheritDoc} - */ - public function supportsType($type) - { - return $type === 'accompanying_period_closing'; - } - - /** - * - * {@inheritDoc} - */ public function fetchQuery($context, array $args) { $metadata = $this->em - ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod'); - + ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod'); + $data = $this->basicFetchQuery($context, $args); - + $data['type'] = 'accompanying_period_closing'; $data['date'] = $metadata->getColumnName('closingDate'); - $data['WHERE'] = sprintf('%s = %d AND %s IS NOT NULL', - $metadata - ->getAssociationMapping('person')['joinColumns'][0]['name'], - $args['person']->getId(), - $metadata->getColumnName('closingDate')) - ; - + $data['WHERE'] = sprintf( + '%s = %d AND %s IS NOT NULL', + $metadata + ->getAssociationMapping('person')['joinColumns'][0]['name'], + $args['person']->getId(), + $metadata->getColumnName('closingDate') + ); + return $data; } - /** - * - * {@inheritDoc} - */ public function getEntityTemplate($entity, $context, array $args) { return $this->getBasicEntityTemplate( - 'ChillPersonBundle:Timeline:closing_period.html.twig', - $entity, - $context, - $args - ); + 'ChillPersonBundle:Timeline:closing_period.html.twig', + $entity, + $context, + $args + ); + } + + public function supportsType($type) + { + return 'accompanying_period_closing' === $type; } } diff --git a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php index f8789b088..7ae96fd6f 100644 --- a/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php +++ b/src/Bundle/ChillPersonBundle/Timeline/TimelineAccompanyingPeriodOpening.php @@ -1,72 +1,44 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; - /** - * Provide information for opening periods to timeline - * - * @author Julien Fastré + * Provide information for opening periods to timeline. */ class TimelineAccompanyingPeriodOpening extends AbstractTimelineAccompanyingPeriod { - - /** - * - * {@inheritDoc} - */ - public function supportsType($type) - { - return $type === 'accompanying_period_opening'; - } - - /** - * - * {@inheritDoc} - */ public function fetchQuery($context, array $args) { $metadata = $this->em - ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod'); - + ->getClassMetadata('ChillPersonBundle:AccompanyingPeriod'); + $data = $this->basicFetchQuery($context, $args); - + $data['type'] = 'accompanying_period_opening'; $data['date'] = $metadata->getColumnName('openingDate'); - + return $data; } - /** - * - * {@inheritDoc} - */ public function getEntityTemplate($entity, $context, array $args) { return $this->getBasicEntityTemplate( - 'ChillPersonBundle:Timeline:opening_period.html.twig', - $entity, - $context, - $args - ); + 'ChillPersonBundle:Timeline:opening_period.html.twig', + $entity, + $context, + $args + ); + } + + public function supportsType($type) + { + return 'accompanying_period_opening' === $type; } } diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/Birthdate.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/Birthdate.php index d09d549fd..1b10270ac 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/Birthdate.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/Birthdate.php @@ -1,20 +1,10 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Validator\Constraints; @@ -23,18 +13,16 @@ use Symfony\Component\Validator\Constraint; /** * Create a constraint on birth date: the birthdate after today are not allowed. - * - * It is possible to add a delay before today, expressed as described in + * + * It is possible to add a delay before today, expressed as described in * interval_spec : http://php.net/manual/en/dateinterval.construct.php * (this interval_spec itself is based on ISO8601 : * https://en.wikipedia.org/wiki/ISO_8601#Durations) - * - * @author Julien Fastré */ class Birthdate extends Constraint { - public $message = "The birthdate must be before %date%"; - + public $message = 'The birthdate must be before %date%'; + public function validatedBy() { return 'birthdate_not_before'; diff --git a/src/Bundle/ChillPersonBundle/Validator/Constraints/BirthdateValidator.php b/src/Bundle/ChillPersonBundle/Validator/Constraints/BirthdateValidator.php index cba955ef6..a9fdb45c0 100644 --- a/src/Bundle/ChillPersonBundle/Validator/Constraints/BirthdateValidator.php +++ b/src/Bundle/ChillPersonBundle/Validator/Constraints/BirthdateValidator.php @@ -1,75 +1,60 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Validator\Constraints; +use DateInterval; +use DateTime; +use LogicException; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; -/** - * - * - * @author Julien Fastré - */ class BirthdateValidator extends ConstraintValidator { - private $interval_spec = null; - + private $interval_spec; + public function __construct($interval_spec = null) { $this->interval_spec = $interval_spec; } - + public function validate($value, Constraint $constraint) { - if ($value === NULL) { - + if (null === $value) { return; } - - if (!$value instanceof \DateTime) { - throw new \LogicException('The input should a be a \DateTime interface,' + + if (!$value instanceof DateTime) { + throw new LogicException('The input should a be a \DateTime interface,' . (is_object($value) ? get_class($value) : gettype($value))); } - + $limitDate = $this->getLimitDate(); - + if ($limitDate < $value) { $this->context->buildViolation($constraint->message) ->setParameter('%date%', $limitDate->format('d-m-Y')) ->addViolation(); } - } - + /** - * - * @return \DateTime + * @return DateTime */ private function getLimitDate() { - if ($this->interval_spec !== NULL) { - $interval = new \DateInterval($this->interval_spec); - return (new \DateTime('now'))->sub($interval); - } else { - return (new \DateTime('now')); - } - } + if (null !== $this->interval_spec) { + $interval = new DateInterval($this->interval_spec); + return (new DateTime('now'))->sub($interval); + } + + return new DateTime('now'); + } } diff --git a/src/Bundle/ChillPersonBundle/Widget/AddAPersonWidget.php b/src/Bundle/ChillPersonBundle/Widget/AddAPersonWidget.php index f886edee9..9e755163d 100644 --- a/src/Bundle/ChillPersonBundle/Widget/AddAPersonWidget.php +++ b/src/Bundle/ChillPersonBundle/Widget/AddAPersonWidget.php @@ -1,9 +1,10 @@ render("ChillPersonBundle:Widget:homepage_add_a_person.html.twig"); - } + Environment $env, + $place, + array $context, + array $config + ) { + return $env->render('ChillPersonBundle:Widget:homepage_add_a_person.html.twig'); + } } diff --git a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php index e885e0a26..2ad3344f5 100644 --- a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php +++ b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget.php @@ -1,86 +1,78 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Widget; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Templating\Widget\WidgetInterface; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use DateTime; +use Doctrine\DBAL\Types\Type; +use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\Expr; -use Doctrine\DBAL\Types\Type; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\User\UserInterface; +use RuntimeException; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; -use Chill\PersonBundle\Security\Authorization\PersonVoter; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\EntityManager; -use Chill\CustomFieldsBundle\Entity\CustomField; +use Symfony\Component\Security\Core\User\UserInterface; use Twig\Environment; +use UnexpectedValueException; + +use function array_key_exists; /** - * add a widget with person list. - * + * add a widget with person list. + * * The configuration is defined by `PersonListWidgetFactory` - * - * If the options 'custom_fields' is used, the custom fields entity will be + * + * If the options 'custom_fields' is used, the custom fields entity will be * queried from the db and transmitted to the view under the `customFields` variable. */ class PersonListWidget implements WidgetInterface { /** - * Repository for persons + * the authorization helper. * - * @var EntityRepository + * @var AuthorizationHelper; */ - protected $personRepository; - + protected $authorizationHelper; + /** - * The entity manager + * The entity manager. * * @var EntityManager */ protected $entityManager; - - /** - * the authorization helper - * - * @var AuthorizationHelper; - */ - protected $authorizationHelper; - + /** + * Repository for persons. * + * @var EntityRepository + */ + protected $personRepository; + + /** * @var TokenStorage */ protected $tokenStorage; - + /** - * * @var UserInterface */ protected $user; - + public function __construct( - EntityRepository $personRepostory, - EntityManager $em, - AuthorizationHelper $authorizationHelper, - TokenStorage $tokenStorage - ) { + EntityRepository $personRepostory, + EntityManager $em, + AuthorizationHelper $authorizationHelper, + TokenStorage $tokenStorage + ) { $this->personRepository = $personRepostory; $this->authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; @@ -88,29 +80,26 @@ class PersonListWidget implements WidgetInterface } /** - * * @param type $place - * @param array $context - * @param array $config + * * @return string */ public function render(Environment $env, $place, array $context, array $config) - { + { $numberOfItems = $config['number_of_items'] ?? 20; - + $qb = $this->personRepository - ->createQueryBuilder('person'); - + ->createQueryBuilder('person'); + // show only the person from the authorized centers $and = $qb->expr()->andX(); $centers = $this->authorizationHelper - ->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE)); + ->getReachableCenters($this->getUser(), new Role(PersonVoter::SEE)); $and->add($qb->expr()->in('person.center', ':centers')); $qb->setParameter('centers', $centers); - // add the "only active" query - if (\array_key_exists('only_active', $config) && $config['only_active'] === true) { + if (array_key_exists('only_active', $config) && true === $config['only_active']) { $qb->join('person.accompanyingPeriods', 'ap'); $or = new Expr\Orx(); // add the case where closingDate IS NULL @@ -120,85 +109,88 @@ class PersonListWidget implements WidgetInterface $or->add($andWhenClosingDateIsNull); // add the case when closingDate is in the future $or->add( - (new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate') - ); + (new Expr())->between(':now', 'ap.openingDate', 'ap.closingDate') + ); $and->add($or); - $qb->setParameter('now', new \DateTime(), Type::DATE); + $qb->setParameter('now', new DateTime(), Type::DATE); } - - if (\array_key_exists('filtering_class', $config) && $config['filtering_class'] !== NULL) { - $filteringClass = new $config['filtering_class']; - if ( ! $filteringClass instanceof PersonListWidget\PersonFilteringInterface) { - throw new \UnexpectedValueException(sprintf("the class %s does not " - . "implements %s", $config['filtering_class'], - PersonListWidget\PersonFilteringInterface::class)); + if (array_key_exists('filtering_class', $config) && null !== $config['filtering_class']) { + $filteringClass = new $config['filtering_class'](); + + if (!$filteringClass instanceof PersonListWidget\PersonFilteringInterface) { + throw new UnexpectedValueException(sprintf( + 'the class %s does not ' + . 'implements %s', + $config['filtering_class'], + PersonListWidget\PersonFilteringInterface::class + )); } - $ids = $filteringClass->getPersonIds($this->entityManager, - $this->getUser()); + $ids = $filteringClass->getPersonIds( + $this->entityManager, + $this->getUser() + ); $in = (new Expr())->in('person.id', ':ids'); $and->add($in); $qb->setParameter('ids', $ids); } - + // adding the where clause to the query $qb->where($and); - + // ordering the query by lastname, firstname $qb->addOrderBy('person.lastName', 'ASC') - ->addOrderBy('person.firstName', 'ASC'); - - + ->addOrderBy('person.firstName', 'ASC'); + $qb->setFirstResult(0)->setMaxResults($numberOfItems); - + $persons = $qb->getQuery()->getResult(); - - // get some custom field when the view is overriden and we want to + + // get some custom field when the view is overriden and we want to // show some custom field in the overriden view. - $cfields = array(); + $cfields = []; + if (isset($config['custom_fields'])) { if (count($config['custom_fields']) > 0) { $cfs = $this->entityManager - ->getRepository('ChillCustomFieldsBundle:CustomField') - ->findBy(array('slug' => $config['custom_fields'])); + ->getRepository('ChillCustomFieldsBundle:CustomField') + ->findBy(['slug' => $config['custom_fields']]); // store the custom fields in a array - foreach($cfs as $cf) { + foreach ($cfs as $cf) { $cfields[$cf->getSlug()] = $cf; } } - } + } return $env->render( 'ChillPersonBundle:Widget:homepage_person_list.html.twig', - array( + [ 'persons' => $persons, - 'customFields' => $cfields - - ) - ); + 'customFields' => $cfields, + ] + ); } - + /** - * + * @throws RuntimeException + * * @return UserInterface - * @throws \RuntimeException */ private function getUser() { $token = $this->tokenStorage->getToken(); - - if ($token === null) { - throw new \RuntimeException("the token should not be null"); + + if (null === $token) { + throw new RuntimeException('the token should not be null'); } - + $user = $token->getUser(); - - if (!$user instanceof UserInterface || $user == null) { - throw new \RuntimeException("the user should implement UserInterface. " - . "Are you logged in ?"); + + if (!$user instanceof UserInterface || null == $user) { + throw new RuntimeException('the user should implement UserInterface. ' + . 'Are you logged in ?'); } - + return $user; } - -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php index 555884cc1..782d01ba9 100644 --- a/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php +++ b/src/Bundle/ChillPersonBundle/Widget/PersonListWidget/PersonFilteringInterface.php @@ -1,33 +1,21 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Widget\PersonListWidget; -use Doctrine\ORM\EntityManager; use Chill\MainBundle\Entity\User; - +use Doctrine\ORM\EntityManager; /** * Interface to implement on classes called in configuration for - * PersonListWidget (`person_list`), under the key `filtering_class` : - * + * PersonListWidget (`person_list`), under the key `filtering_class` :. + * * ``` * widgets: * homepage: @@ -35,50 +23,48 @@ use Chill\MainBundle\Entity\User; * # where \FQDN\To\Class implements PersonFiltering * class_filtering: \FQDN\To\Class * ``` - * */ -interface PersonFilteringInterface +interface PersonFilteringInterface { /** * Return an array of persons id to show. - * - * Those ids are inserted into the query like this (where ids is the array + * + * Those ids are inserted into the query like this (where ids is the array * returned by this class) : - * + * * ``` - * SELECT p FROM ChillPersonBundle:Persons p + * SELECT p FROM ChillPersonBundle:Persons p * WHERE p.id IN (:ids) - * AND + * AND * -- security/authorization statement: restraint person to authorized centers * p.center in :authorized_centers * ``` - * + * * Example of use : filtering based on custom field data : * ``` - - class HomepagePersonFiltering implements PersonFilteringInterface { - - public function getPersonIds(EntityManager $em, User $user) - { - $rsmBuilder = new ResultSetMappingBuilder($em); - $rsmBuilder->addScalarResult('id', 'id', Type::BIGINT); - - $personTable = $em->getClassMetadata('ChillPersonBundle:Person') - ->getTableName(); - $personIdColumn = $em->getClassMetadata('ChillPersonBundle:Person') - ->getColumnName('id'); - $personCfDataColumn = $em->getClassMetadata('ChillPersonBundle:Person') - ->getColumnName('cfData'); - - return $em->createNativeQuery(sprintf("SELECT %s FROM %s WHERE " - . "jsonb_exists(%s, 'school-2fb5440e-192c-11e6-b2fd-74d02b0c9b55')", - $personIdColumn, $personTable, $personCfDataColumn), $rsmBuilder) - ->getScalarResult(); - } -} + * + * class HomepagePersonFiltering implements PersonFilteringInterface { + * + * public function getPersonIds(EntityManager $em, User $user) + * { + * $rsmBuilder = new ResultSetMappingBuilder($em); + * $rsmBuilder->addScalarResult('id', 'id', Type::BIGINT); + * + * $personTable = $em->getClassMetadata('ChillPersonBundle:Person') + * ->getTableName(); + * $personIdColumn = $em->getClassMetadata('ChillPersonBundle:Person') + * ->getColumnName('id'); + * $personCfDataColumn = $em->getClassMetadata('ChillPersonBundle:Person') + * ->getColumnName('cfData'); + * + * return $em->createNativeQuery(sprintf("SELECT %s FROM %s WHERE " + * . "jsonb_exists(%s, 'school-2fb5440e-192c-11e6-b2fd-74d02b0c9b55')", + * $personIdColumn, $personTable, $personCfDataColumn), $rsmBuilder) + * ->getScalarResult(); + * } + * } * ``` - * - * @param EntityManager $em + * * @return int[] an array of persons id to show */ public function getPersonIds(EntityManager $em, User $user); diff --git a/src/Bundle/ChillPersonBundle/Widget/PersonListWidgetFactory.php b/src/Bundle/ChillPersonBundle/Widget/PersonListWidgetFactory.php index 7913caa86..a320e57c2 100644 --- a/src/Bundle/ChillPersonBundle/Widget/PersonListWidgetFactory.php +++ b/src/Bundle/ChillPersonBundle/Widget/PersonListWidgetFactory.php @@ -1,27 +1,17 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\PersonBundle\Widget; use Chill\MainBundle\DependencyInjection\Widget\Factory\AbstractWidgetFactory; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\Definition\Builder\NodeBuilder; +use Symfony\Component\DependencyInjection\ContainerBuilder; /** * add configuration for the person_list widget. @@ -31,36 +21,35 @@ class PersonListWidgetFactory extends AbstractWidgetFactory public function configureOptions($place, NodeBuilder $node) { $node->booleanNode('only_active') - ->defaultTrue() - ->end(); + ->defaultTrue() + ->end(); $node->integerNode('number_of_items') ->defaultValue(50) ->end(); $node->scalarNode('filtering_class') - ->defaultNull() - ->end(); + ->defaultNull() + ->end(); $node->arrayNode('custom_fields') - ->prototype('scalar')->end() - ->info("Add some custom field to the view. Add the slug of some custom field" - . " if you want to override the view and show their value in the list") - ->example(array("custom-field-slug-1", "custom-field-slug-2")) - ->requiresAtLeastOneElement() - ->end(); + ->prototype('scalar')->end() + ->info('Add some custom field to the view. Add the slug of some custom field' + . ' if you want to override the view and show their value in the list') + ->example(['custom-field-slug-1', 'custom-field-slug-2']) + ->requiresAtLeastOneElement() + ->end(); } - + public function getAllowedPlaces() { - return array('homepage'); + return ['homepage']; } - - public function getWidgetAlias() - { - return 'person_list'; - } - + public function getServiceId(ContainerBuilder $containerBuilder, $place, $order, array $config) { return 'chill_person.widget.person_list'; } - + + public function getWidgetAlias() + { + return 'person_list'; + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20141129010948.php b/src/Bundle/ChillPersonBundle/migrations/Version20141129010948.php index bb0ae1850..fffc11496 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20141129010948.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20141129010948.php @@ -1,44 +1,49 @@ addSql("CREATE SEQUENCE ClosingMotive_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE person_history_file_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE SEQUENCE Person_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE TABLE ClosingMotive (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE TABLE person_history_file (id INT NOT NULL, person_id INT DEFAULT NULL, date_opening DATE NOT NULL, date_closing DATE DEFAULT NULL, memo TEXT NOT NULL, closingMotive_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_64A4A621217BBB47 ON person_history_file (person_id);"); - $this->addSql("CREATE INDEX IDX_64A4A621504CB38D ON person_history_file (closingMotive_id);"); - $this->addSql("CREATE TABLE Person (id INT NOT NULL, nationality_id INT DEFAULT NULL, firstName VARCHAR(255) NOT NULL, lastName VARCHAR(255) NOT NULL, date_of_birth DATE DEFAULT NULL, place_of_birth VARCHAR(255) NOT NULL, genre VARCHAR(9) NOT NULL, memo TEXT NOT NULL, email TEXT NOT NULL, proxyHistoryOpenState BOOLEAN NOT NULL, cFData TEXT NOT NULL, phonenumber TEXT DEFAULT NULL, countryOfBirth_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_3370D4403818DA5 ON Person (countryOfBirth_id);"); - $this->addSql("CREATE INDEX IDX_3370D4401C9DA55 ON Person (nationality_id);"); - $this->addSql("CREATE INDEX person_names ON Person (firstName, lastName);"); - $this->addSql("COMMENT ON COLUMN Person.cFData IS '(DC2Type:array)';"); - $this->addSql("CREATE TABLE persons_spoken_languages (person_id INT NOT NULL, language_id VARCHAR(255) NOT NULL, PRIMARY KEY(person_id, language_id));"); - $this->addSql("CREATE INDEX IDX_7201106F217BBB47 ON persons_spoken_languages (person_id);"); - $this->addSql("CREATE INDEX IDX_7201106F82F1BAF4 ON persons_spoken_languages (language_id);"); - $this->addSql("ALTER TABLE person_history_file ADD CONSTRAINT FK_64A4A621217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE person_history_file ADD CONSTRAINT FK_64A4A621504CB38D FOREIGN KEY (closingMotive_id) REFERENCES ClosingMotive (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE Person ADD CONSTRAINT FK_3370D4403818DA5 FOREIGN KEY (countryOfBirth_id) REFERENCES Country (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE Person ADD CONSTRAINT FK_3370D4401C9DA55 FOREIGN KEY (nationality_id) REFERENCES Country (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE persons_spoken_languages ADD CONSTRAINT FK_7201106F217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE persons_spoken_languages ADD CONSTRAINT FK_7201106F82F1BAF4 FOREIGN KEY (language_id) REFERENCES Language (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;"); - - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs + } + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE ClosingMotive_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE person_history_file_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE SEQUENCE Person_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE TABLE ClosingMotive (id INT NOT NULL, name JSON NOT NULL, active BOOLEAN NOT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE TABLE person_history_file (id INT NOT NULL, person_id INT DEFAULT NULL, date_opening DATE NOT NULL, date_closing DATE DEFAULT NULL, memo TEXT NOT NULL, closingMotive_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_64A4A621217BBB47 ON person_history_file (person_id);'); + $this->addSql('CREATE INDEX IDX_64A4A621504CB38D ON person_history_file (closingMotive_id);'); + $this->addSql('CREATE TABLE Person (id INT NOT NULL, nationality_id INT DEFAULT NULL, firstName VARCHAR(255) NOT NULL, lastName VARCHAR(255) NOT NULL, date_of_birth DATE DEFAULT NULL, place_of_birth VARCHAR(255) NOT NULL, genre VARCHAR(9) NOT NULL, memo TEXT NOT NULL, email TEXT NOT NULL, proxyHistoryOpenState BOOLEAN NOT NULL, cFData TEXT NOT NULL, phonenumber TEXT DEFAULT NULL, countryOfBirth_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_3370D4403818DA5 ON Person (countryOfBirth_id);'); + $this->addSql('CREATE INDEX IDX_3370D4401C9DA55 ON Person (nationality_id);'); + $this->addSql('CREATE INDEX person_names ON Person (firstName, lastName);'); + $this->addSql("COMMENT ON COLUMN Person.cFData IS '(DC2Type:array)';"); + $this->addSql('CREATE TABLE persons_spoken_languages (person_id INT NOT NULL, language_id VARCHAR(255) NOT NULL, PRIMARY KEY(person_id, language_id));'); + $this->addSql('CREATE INDEX IDX_7201106F217BBB47 ON persons_spoken_languages (person_id);'); + $this->addSql('CREATE INDEX IDX_7201106F82F1BAF4 ON persons_spoken_languages (language_id);'); + $this->addSql('ALTER TABLE person_history_file ADD CONSTRAINT FK_64A4A621217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE person_history_file ADD CONSTRAINT FK_64A4A621504CB38D FOREIGN KEY (closingMotive_id) REFERENCES ClosingMotive (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE Person ADD CONSTRAINT FK_3370D4403818DA5 FOREIGN KEY (countryOfBirth_id) REFERENCES Country (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE Person ADD CONSTRAINT FK_3370D4401C9DA55 FOREIGN KEY (nationality_id) REFERENCES Country (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE persons_spoken_languages ADD CONSTRAINT FK_7201106F217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE persons_spoken_languages ADD CONSTRAINT FK_7201106F82F1BAF4 FOREIGN KEY (language_id) REFERENCES Language (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20150212173934.php b/src/Bundle/ChillPersonBundle/migrations/Version20150212173934.php index 94c3f038c..d14368d89 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150212173934.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150212173934.php @@ -1,30 +1,36 @@ addSql('ALTER TABLE accompanying_period RENAME TO person_history_file;'); + $this->addSql('ALTER TABLE person RENAME proxyAccompanyingPeriodOpenState TO proxyHistoryOpenState;'); + $this->addSql('ALTER SEQUENCE accompanying_period_id_seq RENAME TO person_history_file_id_seq;'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->addSql("ALTER TABLE person RENAME proxyHistoryOpenState TO proxyAccompanyingPeriodOpenState;"); - $this->addSql("ALTER TABLE person_history_file RENAME TO accompanying_period;"); - $this->addSql("ALTER SEQUENCE person_history_file_id_seq RENAME TO accompanying_period_id_seq;"); - - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql("ALTER TABLE accompanying_period RENAME TO person_history_file;"); - $this->addSql("ALTER TABLE person RENAME proxyAccompanyingPeriodOpenState TO proxyHistoryOpenState;"); - $this->addSql("ALTER SEQUENCE accompanying_period_id_seq RENAME TO person_history_file_id_seq;"); + $this->addSql('ALTER TABLE person RENAME proxyHistoryOpenState TO proxyAccompanyingPeriodOpenState;'); + $this->addSql('ALTER TABLE person_history_file RENAME TO accompanying_period;'); + $this->addSql('ALTER SEQUENCE person_history_file_id_seq RENAME TO accompanying_period_id_seq;'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php b/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php index 71a603a2f..c5bb68215 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150607231010.php @@ -1,26 +1,41 @@ abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + $this->addSql('ALTER TABLE Person DROP CONSTRAINT FK_person_center'); + $this->addSql('DROP INDEX IDX_person_center'); + $this->addSql('ALTER TABLE Person DROP center_id'); + } + public function getDescription(): string { return 'Add a center on the person entity. The default center is the first ' . 'recorded.'; } - - /** - * @param Schema $schema - */ public function up(Schema $schema): void { $this->abortIf( @@ -37,7 +52,7 @@ class Version20150607231010 extends AbstractMigration //check if there are data in person table $nbPeople = $this->connection->fetchColumn('SELECT count(*) FROM person'); - if ($nbPeople > 0) { + if (0 < $nbPeople) { // we have data ! We have to create a center ! $newCenterId = $this->connection->fetchColumn('SELECT nextval(\'centers_id_seq\');'); $this->addSql( @@ -51,7 +66,7 @@ class Version20150607231010 extends AbstractMigration $this->addSql('ALTER TABLE person ADD center_id INT'); if (isset($defaultCenterId)) { - $this->addSql('UPDATE person SET center_id = :id', array('id' => $defaultCenterId)); + $this->addSql('UPDATE person SET center_id = :id', ['id' => $defaultCenterId]); } $this->addSql('ALTER TABLE person ' @@ -60,19 +75,4 @@ class Version20150607231010 extends AbstractMigration $this->addSql('ALTER TABLE person ALTER center_id SET NOT NULL'); $this->addSql('CREATE INDEX IDX_person_center ON person (center_id)'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf( - $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.' - ); - - $this->addSql('ALTER TABLE Person DROP CONSTRAINT FK_person_center'); - $this->addSql('DROP INDEX IDX_person_center'); - $this->addSql('ALTER TABLE Person DROP center_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20150811152608.php b/src/Bundle/ChillPersonBundle/migrations/Version20150811152608.php index c14ede4a5..4d825878b 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150811152608.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150811152608.php @@ -1,66 +1,44 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Person; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** * Migration for adapting the Person Bundle to the 'cahier de charge' : * - RENAMING : * - - date_of_birth TO birthdate - * - - genre to gender - * + * - - genre to gender. */ class Version20150811152608 extends AbstractMigration { - /** - * @param Schema $schema - */ - public function up(Schema $schema): void - { - $this->abortIf( - $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE person RENAME COLUMN date_of_birth TO birthdate'); - $this->addSql('ALTER TABLE person RENAME COLUMN genre TO gender'); - - - - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->abortIf( $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); + 'Migration can only be executed safely on \'postgresql\'.' + ); $this->addSql('ALTER TABLE person RENAME COLUMN birthdate TO date_of_birth'); $this->addSql('ALTER TABLE person RENAME COLUMN gender TO genre'); + } + public function up(Schema $schema): void + { + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + $this->addSql('ALTER TABLE person RENAME COLUMN date_of_birth TO birthdate'); + $this->addSql('ALTER TABLE person RENAME COLUMN genre TO gender'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20150812110708.php b/src/Bundle/ChillPersonBundle/migrations/Version20150812110708.php index efe46d436..f4bfb1031 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150812110708.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150812110708.php @@ -1,43 +1,40 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Person; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** - * Migration for adding maritalstatus to person + * Migration for adding maritalstatus to person. */ class Version20150812110708 extends AbstractMigration { - /** - * @param Schema $schema - */ + public function down(Schema $schema): void + { + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + $this->addSql('ALTER TABLE person DROP CONSTRAINT fk_person_marital_status;'); + $this->addSql('ALTER TABLE person DROP COLUMN maritalstatus_id;'); + $this->addSql('DROP TABLE marital_status;'); + } + public function up(Schema $schema): void { $this->abortIf( $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); + 'Migration can only be executed safely on \'postgresql\'.' + ); $this->addSql('CREATE TABLE marital_status ( id character varying(10) NOT NULL, @@ -46,18 +43,4 @@ class Version20150812110708 extends AbstractMigration $this->addSql('ALTER TABLE person ADD COLUMN maritalstatus_id character varying(10)'); $this->addSql('ALTER TABLE person ADD CONSTRAINT fk_person_marital_status FOREIGN KEY (maritalstatus_id) REFERENCES marital_status (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf( - $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE person DROP CONSTRAINT fk_person_marital_status;'); - $this->addSql('ALTER TABLE person DROP COLUMN maritalstatus_id;'); - $this->addSql('DROP TABLE marital_status;'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20150820113409.php b/src/Bundle/ChillPersonBundle/migrations/Version20150820113409.php index 4e99cf185..2ae72b302 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20150820113409.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20150820113409.php @@ -1,61 +1,44 @@ , - * - * 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 . + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\Migrations\Person; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; +use Doctrine\Migrations\AbstractMigration; /** * Migration for adapting the Person Bundle to the 'cahier de charge' : - * - update of accompanyingPerid + * - update of accompanyingPerid. */ class Version20150820113409 extends AbstractMigration { - /** - * @param Schema $schema - */ - public function up(Schema $schema): void - { - $this->abortIf( - $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN date_opening TO openingdate;'); - $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN date_closing TO closingdate;'); - $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN memo TO remark;'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->abortIf( $this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); + 'Migration can only be executed safely on \'postgresql\'.' + ); $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN openingdate TO date_opening;'); $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN closingdate TO date_closing;'); $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN remark TO memo;'); } + + public function up(Schema $schema): void + { + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN date_opening TO openingdate;'); + $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN date_closing TO closingdate;'); + $this->addSql('ALTER TABLE accompanying_period RENAME COLUMN memo TO remark;'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20160310161006.php b/src/Bundle/ChillPersonBundle/migrations/Version20160310161006.php index 847802f94..c808b9e17 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20160310161006.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20160310161006.php @@ -1,18 +1,29 @@ abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP TABLE chill_person_persons_to_addresses'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -35,15 +46,4 @@ class Version20160310161006 extends AbstractMigration . 'FOREIGN KEY (address_id) ' . 'REFERENCES chill_main_address (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP TABLE chill_person_persons_to_addresses'); - - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20160422000000.php b/src/Bundle/ChillPersonBundle/migrations/Version20160422000000.php index 3bfba03d9..c38ab92c0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20160422000000.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20160422000000.php @@ -1,18 +1,26 @@ connection->query('SELECT COUNT(*), pe.id, ad.validfrom FROM person AS pe @@ -20,23 +28,16 @@ class Version20160422000000 extends AbstractMigration INNER JOIN chill_main_address AS ad ON ad.id = pe_ad.address_id GROUP BY pe.id, ad.validfrom HAVING COUNT(*) > 1'); - + $personWithTwoAddressWithSameValidFrom = $stmt->fetchAll(); - + foreach ($personWithTwoAddressWithSameValidFrom as $p) { - $this->warnIf(true, 'The person with id '.$p['id'].' has two adresses with the same validFrom date'); + $this->warnIf(true, 'The person with id ' . $p['id'] . ' has two adresses with the same validFrom date'); } - + $this->abortIf( sizeof($personWithTwoAddressWithSameValidFrom) != 0, 'There exists some person with multiple adress with the same validFrom' ); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20160818113633.php b/src/Bundle/ChillPersonBundle/migrations/Version20160818113633.php index b8ca9d8db..ea8e335ef 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20160818113633.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20160818113633.php @@ -1,21 +1,36 @@ addSQL('ALTER TABLE person DROP COLUMN cfdata'); + $this->addSQL('ALTER TABLE person RENAME COLUMN cfdata_old TO cfdata'); + $this->addSql('ALTER TABLE person ALTER COLUMN cfdata SET NOT NULL'); + } + /** * Make a copy of the column cfdata into the column cfdata_old. Then * remplace the sterialized data into a json data. - * - * @param Schema $schema */ public function up(Schema $schema): void { @@ -35,16 +50,4 @@ class Version20160818113633 extends AbstractMigration ); } } - - /** - * Inverse of up - * - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->addSQL('ALTER TABLE person DROP COLUMN cfdata'); - $this->addSQL('ALTER TABLE person RENAME COLUMN cfdata_old TO cfdata'); - $this->addSql('ALTER TABLE person ALTER COLUMN cfdata SET NOT NULL'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20160818151130.php b/src/Bundle/ChillPersonBundle/migrations/Version20160818151130.php index ea58ce5c3..5f306bd4c 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20160818151130.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20160818151130.php @@ -1,35 +1,22 @@ addSql('ALTER TABLE person RENAME TO chill_person_person'); - $this->addSql('ALTER TABLE person_id_seq RENAME TO chill_person_person_id_seq'); - - $this->addSql('ALTER TABLE marital_status RENAME TO chill_person_marital_status'); - - $this->addSql('ALTER TABLE accompanying_period RENAME TO chill_person_accompanying_period'); - $this->addSql('ALTER TABLE accompanying_period_id_seq RENAME TO chill_person_accompanying_period_id_seq'); - - $this->addSql('ALTER TABLE closingmotive RENAME TO chill_person_closingmotive'); - $this->addSql('ALTER TABLE closingmotive_id_seq RENAME TO chill_person_closingmotive_id_seq'); - } - - /** - * @param Schema $schema - */ public function down(Schema $schema): void { $this->addSQL('ALTER TABLE chill_person_person RENAME TO person'); @@ -43,4 +30,18 @@ class Version20160818151130 extends AbstractMigration $this->addSQL('ALTER TABLE chill_person_closingmotive RENAME TO closingmotive'); $this->addSql('ALTER TABLE chill_person_closingmotive_id_seq RENAME TO closingmotive_id_seq'); } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE person RENAME TO chill_person_person'); + $this->addSql('ALTER TABLE person_id_seq RENAME TO chill_person_person_id_seq'); + + $this->addSql('ALTER TABLE marital_status RENAME TO chill_person_marital_status'); + + $this->addSql('ALTER TABLE accompanying_period RENAME TO chill_person_accompanying_period'); + $this->addSql('ALTER TABLE accompanying_period_id_seq RENAME TO chill_person_accompanying_period_id_seq'); + + $this->addSql('ALTER TABLE closingmotive RENAME TO chill_person_closingmotive'); + $this->addSql('ALTER TABLE closingmotive_id_seq RENAME TO chill_person_closingmotive_id_seq'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20170117131924.php b/src/Bundle/ChillPersonBundle/migrations/Version20170117131924.php index 0b9988760..91157be03 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20170117131924.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20170117131924.php @@ -1,123 +1,125 @@ 'integer', - 'streetaddress1' => 'varchar(255)', - 'streetaddress2' => 'varchar(255)', - 'validfrom' => 'date', - 'postcode_label' => 'varchar(255)', - 'postcode_code' => 'varchar(100)', - 'postcode_id' => 'integer', - 'country_name' => 'json', - 'country_code' => 'varchar(3)', - 'country_id' => 'integer' - ); - - /** - * @param Schema $schema - */ - public function up(Schema $schema): void - { - $this->addSql(<<<'SQL' -CREATE OR REPLACE FUNCTION public.get_last_address ( - pid integer, - before_date date) -RETURNS TABLE( - person_id integer, - address_id integer, - streetaddress1 varchar(255), - streetaddress2 varchar(255), - validfrom date, - postcode_label varchar(255), - postcode_code varchar(100), - postcode_id integer, - country_name json, - country_code varchar(3), - country_id integer) - AS -$BODY$ -SELECT - pid AS person_id, - chill_main_address.id AS address_id, - chill_main_address.streetaddress1, - chill_main_address.streetaddress2, - chill_main_address.validfrom, - chill_main_postal_code.label, - chill_main_postal_code.code, - chill_main_postal_code.id AS postal_code_id, - country.name, - country.countrycode, - country.id AS country_id -FROM chill_main_address -JOIN ( - SELECT - chill_main_address.id AS address_id, - validfrom, - rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos - FROM chill_person_persons_to_addresses - JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id - WHERE person_id = pid - AND chill_main_address.validfrom <= before_date -) AS ranking ON ranking.address_id = chill_main_address.id -JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id -JOIN country ON chill_main_postal_code.country_id = country.id -WHERE ranking.pos = 1 -$BODY$ -LANGUAGE sql VOLATILE -COST 100; -SQL - ); - - // create function to get part of address - foreach ($this->fields as $var => $type) { - $this->addSql(sprintf(<<<'SQL' -CREATE OR REPLACE FUNCTION get_last_address_%s ( - pid integer, - before_date date) -RETURNS %s AS -$BODY$ -SELECT %s FROM get_last_address(pid, before_date) -$BODY$ -LANGUAGE sql volatile -COST 100; -SQL - , $var, $type, $var)); - } - } + public $fields = [ + 'address_id' => 'integer', + 'streetaddress1' => 'varchar(255)', + 'streetaddress2' => 'varchar(255)', + 'validfrom' => 'date', + 'postcode_label' => 'varchar(255)', + 'postcode_code' => 'varchar(100)', + 'postcode_id' => 'integer', + 'country_name' => 'json', + 'country_code' => 'varchar(3)', + 'country_id' => 'integer', + ]; - /** - * @param Schema $schema - */ public function down(Schema $schema): void { // drop function to get parts of address foreach ($this->fields as $var => $type) { - $this->addSql(<<addSql( + <<addSQL(<<addSQL( + <<<'SQL' + DROP FUNCTION public.get_last_address ( + pid integer, + before_date date) + SQL + ); + } + + public function up(Schema $schema): void + { + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION public.get_last_address ( + pid integer, + before_date date) + RETURNS TABLE( + person_id integer, + address_id integer, + streetaddress1 varchar(255), + streetaddress2 varchar(255), + validfrom date, + postcode_label varchar(255), + postcode_code varchar(100), + postcode_id integer, + country_name json, + country_code varchar(3), + country_id integer) + AS + $BODY$ + SELECT + pid AS person_id, + chill_main_address.id AS address_id, + chill_main_address.streetaddress1, + chill_main_address.streetaddress2, + chill_main_address.validfrom, + chill_main_postal_code.label, + chill_main_postal_code.code, + chill_main_postal_code.id AS postal_code_id, + country.name, + country.countrycode, + country.id AS country_id + FROM chill_main_address + JOIN ( + SELECT + chill_main_address.id AS address_id, + validfrom, + rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos + FROM chill_person_persons_to_addresses + JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id + WHERE person_id = pid + AND chill_main_address.validfrom <= before_date + ) AS ranking ON ranking.address_id = chill_main_address.id + JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id + JOIN country ON chill_main_postal_code.country_id = country.id + WHERE ranking.pos = 1 + $BODY$ + LANGUAGE sql VOLATILE + COST 100; + SQL + ); + + // create function to get part of address + foreach ($this->fields as $var => $type) { + $this->addSql(sprintf(<<<'SQL' + CREATE OR REPLACE FUNCTION get_last_address_%s ( + pid integer, + before_date date) + RETURNS %s AS + $BODY$ + SELECT %s FROM get_last_address(pid, before_date) + $BODY$ + LANGUAGE sql volatile + COST 100; + SQL + , $var, $type, $var)); + } } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20180518144221.php b/src/Bundle/ChillPersonBundle/migrations/Version20180518144221.php index 99309e6a5..18d86b90c 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20180518144221.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20180518144221.php @@ -1,24 +1,24 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_person_person ADD contactInfo TEXT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_person ADD mobilenumber TEXT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_person ALTER email DROP NOT NULL'); - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -27,4 +27,13 @@ final class Version20180518144221 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_person DROP mobilenumber'); $this->addSql('ALTER TABLE chill_person_person ALTER email SET NOT NULL'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_person_person ADD contactInfo TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_person ADD mobilenumber TEXT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_person ALTER email DROP NOT NULL'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20180820120000.php b/src/Bundle/ChillPersonBundle/migrations/Version20180820120000.php index aee4226f1..84a251fd4 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20180820120000.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20180820120000.php @@ -1,26 +1,26 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('UPDATE chill_person_person SET contactInfo=email'); - $this->addSql('UPDATE chill_person_person SET email=\'\''); - - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -28,4 +28,12 @@ final class Version20180820120000 extends AbstractMigration $this->addSql('UPDATE chill_person_person SET email=contactInfo'); $this->addSql('UPDATE chill_person_person SET contactInfo=\'\''); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('UPDATE chill_person_person SET contactInfo=email'); + $this->addSql('UPDATE chill_person_person SET email=\'\''); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20181005140249.php b/src/Bundle/ChillPersonBundle/migrations/Version20181005140249.php index 21a155fb5..2c570b9a0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20181005140249.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20181005140249.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_person_person ALTER gender DROP NOT NULL'); - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); $this->addSql('ALTER TABLE chill_person_person ALTER gender SET NOT NULL'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_person_person ALTER gender DROP NOT NULL'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20181023101621.php b/src/Bundle/ChillPersonBundle/migrations/Version20181023101621.php index 287c7bd7e..51a3492de 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20181023101621.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20181023101621.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql("ALTER TABLE chill_person_person ADD fullnameCanonical VARCHAR(255) DEFAULT '' "); - $this->addSql("UPDATE chill_person_person SET fullnameCanonical=LOWER(UNACCENT(CONCAT(firstname, ' ', lastname)))"); - $this->addSql("CREATE INDEX fullnameCanonical_trgm_idx ON chill_person_person USING GIN (fullnameCanonical gin_trgm_ops)"); - - $this->addSql(<<<'SQL' - CREATE OR REPLACE FUNCTION canonicalize_fullname_on_update() RETURNS TRIGGER AS - $BODY$ - BEGIN - IF NEW.firstname <> OLD.firstname OR NEW.lastname <> OLD.lastname - THEN - UPDATE chill_person_person - SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) - WHERE id=NEW.id; - END IF; - RETURN NEW; - END; - $BODY$ LANGUAGE PLPGSQL; -SQL - ); - $this->addSql(<<addSql(<<<'SQL' - CREATE OR REPLACE FUNCTION canonicalize_fullname_on_insert() RETURNS TRIGGER AS - $BODY$ - BEGIN - UPDATE chill_person_person - SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) - WHERE id=NEW.id; - RETURN NEW; - END; - $BODY$ LANGUAGE PLPGSQL; -SQL - ); - $this->addSql(<<abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -76,4 +30,63 @@ SQL $this->addSql('DROP TRIGGER canonicalize_fullname_on_insert ON chill_person_person'); $this->addSql('DROP FUNCTION canonicalize_fullname_on_insert()'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql("ALTER TABLE chill_person_person ADD fullnameCanonical VARCHAR(255) DEFAULT '' "); + $this->addSql("UPDATE chill_person_person SET fullnameCanonical=LOWER(UNACCENT(CONCAT(firstname, ' ', lastname)))"); + $this->addSql('CREATE INDEX fullnameCanonical_trgm_idx ON chill_person_person USING GIN (fullnameCanonical gin_trgm_ops)'); + + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION canonicalize_fullname_on_update() RETURNS TRIGGER AS + $BODY$ + BEGIN + IF NEW.firstname <> OLD.firstname OR NEW.lastname <> OLD.lastname + THEN + UPDATE chill_person_person + SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) + WHERE id=NEW.id; + END IF; + RETURN NEW; + END; + $BODY$ LANGUAGE PLPGSQL; + SQL + ); + $this->addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_fullname_on_update + AFTER UPDATE + ON chill_person_person + FOR EACH ROW + WHEN (pg_trigger_depth() = 0) + EXECUTE PROCEDURE canonicalize_fullname_on_update(); + SQL + ); + + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION canonicalize_fullname_on_insert() RETURNS TRIGGER AS + $BODY$ + BEGIN + UPDATE chill_person_person + SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) + WHERE id=NEW.id; + RETURN NEW; + END; + $BODY$ LANGUAGE PLPGSQL; + SQL + ); + $this->addSql( + <<<'SQL' + CREATE TRIGGER canonicalize_fullname_on_insert + AFTER INSERT + ON chill_person_person + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_fullname_on_insert(); + SQL + ); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20190701124238.php b/src/Bundle/ChillPersonBundle/migrations/Version20190701124238.php index abe3a11f2..75ed5aa9c 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20190701124238.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20190701124238.php @@ -1,4 +1,13 @@ -addSql('ALTER TABLE chill_person_accompanying_period ADD user_id INT DEFAULT NULL;'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A868A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); - $this->addSql('CREATE INDEX IDX_E260A868A76ED395 ON chill_person_accompanying_period (user_id);'); - } - public function down(Schema $schema): void { - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP user_id'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP user_id'); + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD user_id INT DEFAULT NULL;'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A868A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('CREATE INDEX IDX_E260A868A76ED395 ON chill_person_accompanying_period (user_id);'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20191106103452.php b/src/Bundle/ChillPersonBundle/migrations/Version20191106103452.php index 43a1da1b3..3d03f61ae 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20191106103452.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20191106103452.php @@ -1,4 +1,13 @@ -addSql("CREATE INDEX phonenumber_trgm_idx - ON public.chill_person_person USING gin - (phonenumber gin_trgm_ops)"); - - $this->addSql("CREATE INDEX mobilenumber_trgm_idx - ON public.chill_person_person USING gin - (mobilenumber gin_trgm_ops)"); - - } - public function down(Schema $schema): void { - $this->addSql("DROP INDEX phonenumber_trgm_idx"); - $this->addSql("DROP INDEX mobilenumber_trgm_idx"); + $this->addSql('DROP INDEX phonenumber_trgm_idx'); + $this->addSql('DROP INDEX mobilenumber_trgm_idx'); + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE INDEX phonenumber_trgm_idx + ON public.chill_person_person USING gin + (phonenumber gin_trgm_ops)'); + + $this->addSql('CREATE INDEX mobilenumber_trgm_idx + ON public.chill_person_person USING gin + (mobilenumber gin_trgm_ops)'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20200128084445.php b/src/Bundle/ChillPersonBundle/migrations/Version20200128084445.php index 26f5f4683..1b06528af 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20200128084445.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20200128084445.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql("CREATE SEQUENCE chill_person_alt_name_id_seq INCREMENT BY 1 MINVALUE 1 START 1"); - $this->addSql("CREATE TABLE chill_person_alt_name (id INT NOT NULL, person_id INT DEFAULT NULL, key VARCHAR(255) NOT NULL, label TEXT NOT NULL, PRIMARY KEY(id))"); - $this->addSql("CREATE INDEX IDX_2628668E217BBB47 ON chill_person_alt_name (person_id)"); - $this->addSql("ALTER TABLE chill_person_alt_name ADD CONSTRAINT FK_2628668E217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE"); - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - $this->addSql("DROP INDEX IDX_2628668E217BBB47"); - $this->addSql("DROP TABLE chill_person_alt_name"); - $this->addSql("DROP SEQUENCE chill_person_alt_name_id_seq"); + $this->addSql('DROP INDEX IDX_2628668E217BBB47'); + $this->addSql('DROP TABLE chill_person_alt_name'); + $this->addSql('DROP SEQUENCE chill_person_alt_name_id_seq'); + } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE SEQUENCE chill_person_alt_name_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_person_alt_name (id INT NOT NULL, person_id INT DEFAULT NULL, key VARCHAR(255) NOT NULL, label TEXT NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_2628668E217BBB47 ON chill_person_alt_name (person_id)'); + $this->addSql('ALTER TABLE chill_person_alt_name ADD CONSTRAINT FK_2628668E217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20200130213446.php b/src/Bundle/ChillPersonBundle/migrations/Version20200130213446.php index 538f3fb86..42c4a553b 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20200130213446.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20200130213446.php @@ -1,4 +1,13 @@ - OLD.fullnameCanonical - THEN - UPDATE chill_person_person - SET fullnameCanonical=fullname_canonicalized - WHERE id=NEW.id; - END IF; - RETURN NEW; -END; -$BODY$; -SQL; - - const CANONICALIZE_FULLNAME_ON_ALT_NAME_ALTER = <<<'SQL' -CREATE OR REPLACE FUNCTION public.canonicalize_fullname_on_alt_name_alter() - RETURNS trigger - LANGUAGE 'plpgsql' - COST 100 - VOLATILE NOT LEAKPROOF -AS $BODY$ -DECLARE - target_person_id INTEGER; - cur_person CURSOR(pid INTEGER) FOR SELECT firstname, lastname FROM chill_person_person WHERE id = pid; - person RECORD; - cur_alt_names CURSOR(pid INTEGER) FOR SELECT label FROM chill_person_alt_name WHERE person_id = pid; - alt_name RECORD; - fullname_canonicalized TEXT; -BEGIN - IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' - THEN target_person_id := NEW.person_id; - ELSE target_person_id := OLD.person_id; - END IF; + fullname_canonicalized := CONCAT(fullname_canonicalized, ' ', + LOWER(UNACCENT(alt_name.label))); + END LOOP; + CLOSE cur_alt_names; + CLOSE cur_person; - OPEN cur_person(pid:=target_person_id); - FETCH cur_person INTO person; - fullname_canonicalized := LOWER(UNACCENT(CONCAT(person.firstname, ' ', person.lastname))); - -- loop over alt names - OPEN cur_alt_names(pid:=target_person_id); - LOOP - FETCH cur_alt_names INTO alt_name; + UPDATE chill_person_person + SET fullnameCanonical=fullname_canonicalized + WHERE id=target_person_id; - EXIT WHEN NOT FOUND; + RETURN NEW; + END; + $BODY$; + SQL; - fullname_canonicalized := CONCAT(fullname_canonicalized, ' ', - LOWER(UNACCENT(alt_name.label))); - END LOOP; - CLOSE cur_alt_names; - CLOSE cur_person; + public const CANONICALIZE_FULLNAME_ON_ALT_NAME_DELETE = <<<'SQL' + CREATE TRIGGER canonicalize_fullname_on_alt_name_delete + AFTER DELETE + ON chill_person_alt_name + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_fullname_on_alt_name_alter(); + SQL; - UPDATE chill_person_person - SET fullnameCanonical=fullname_canonicalized - WHERE id=target_person_id; + public const CANONICALIZE_FULLNAME_ON_ALT_NAME_INSERT = <<<'SQL' + CREATE TRIGGER canonicalize_fullname_on_alt_name_insert + AFTER INSERT + ON chill_person_alt_name + FOR EACH ROW + EXECUTE PROCEDURE canonicalize_fullname_on_alt_name_alter(); + SQL; - RETURN NEW; -END; -$BODY$; -SQL; - - const CANONICALIZE_FULLNAME_ON_ALT_NAME_INSERT = << OLD.fullnameCanonical + THEN + UPDATE chill_person_person + SET fullnameCanonical=fullname_canonicalized + WHERE id=NEW.id; + END IF; + RETURN NEW; + END; + $BODY$; + SQL; + + public function down(Schema $schema): void + { + $this->addSql('DROP TRIGGER canonicalize_fullname_on_alt_name_update ON chill_person_alt_name;'); + $this->addSql('DROP TRIGGER canonicalize_fullname_on_alt_name_insert ON chill_person_alt_name;'); + $this->addSql('DROP TRIGGER canonicalize_fullname_on_alt_name_delete ON chill_person_alt_name;'); + $this->addSql('DROP FUNCTION canonicalize_fullname_on_alt_name_alter();'); + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION canonicalize_fullname_on_update() RETURNS TRIGGER AS + $BODY$ + BEGIN + IF NEW.firstname <> OLD.firstname OR NEW.lastname <> OLD.lastname + THEN + UPDATE chill_person_person + SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) + WHERE id=NEW.id; + END IF; + RETURN NEW; + END; + $BODY$ LANGUAGE PLPGSQL; + SQL + ); + } - const CANONICALIZE_FULLNAME_ON_ALT_NAME_UPDATE = <<addSql("ALTER TABLE chill_person_person ALTER fullnamecanonical TYPE TEXT;"); - $this->addSql("ALTER TABLE chill_person_person ALTER fullnamecanonical DROP DEFAULT;"); + $this->addSql('ALTER TABLE chill_person_person ALTER fullnamecanonical TYPE TEXT;'); + $this->addSql('ALTER TABLE chill_person_person ALTER fullnamecanonical DROP DEFAULT;'); // insert function and triggers $this->addSql(self::CANONICALIZE_FULLNAME_ON_UPDATE); $this->addSql(self::CANONICALIZE_FULLNAME_ON_ALT_NAME_ALTER); $this->addSql(self::CANONICALIZE_FULLNAME_ON_ALT_NAME_INSERT); $this->addSql(self::CANONICALIZE_FULLNAME_ON_ALT_NAME_DELETE); $this->addSql(self::CANONICALIZE_FULLNAME_ON_ALT_NAME_UPDATE); - } - - public function down(Schema $schema): void - { - $this->addSql("DROP TRIGGER canonicalize_fullname_on_alt_name_update ON chill_person_alt_name;"); - $this->addSql("DROP TRIGGER canonicalize_fullname_on_alt_name_insert ON chill_person_alt_name;"); - $this->addSql("DROP TRIGGER canonicalize_fullname_on_alt_name_delete ON chill_person_alt_name;"); - $this->addSql("DROP FUNCTION canonicalize_fullname_on_alt_name_alter();"); - $this->addSql(<<<'SQL' - CREATE OR REPLACE FUNCTION canonicalize_fullname_on_update() RETURNS TRIGGER AS - $BODY$ - BEGIN - IF NEW.firstname <> OLD.firstname OR NEW.lastname <> OLD.lastname - THEN - UPDATE chill_person_person - SET fullnameCanonical=LOWER(UNACCENT(CONCAT(NEW.firstname, ' ', NEW.lastname))) - WHERE id=NEW.id; - END IF; - RETURN NEW; - END; - $BODY$ LANGUAGE PLPGSQL; -SQL - ); - } - } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20200310090632.php b/src/Bundle/ChillPersonBundle/migrations/Version20200310090632.php index 3a32f4bfc..5d43d692a 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20200310090632.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20200310090632.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_person_closingmotive DROP parent_id'); + $this->addSql('ALTER TABLE chill_person_closingmotive DROP ordering'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -20,12 +37,4 @@ final class Version20200310090632 extends AbstractMigration $this->addSql('CREATE INDEX IDX_92351ECE727ACA70 ON chill_person_closingmotive (parent_id)'); $this->addsql("ALTER TABLE chill_person_closingmotive ADD ordering DOUBLE PRECISION DEFAULT '0' NOT NULL;"); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_person_closingmotive DROP parent_id'); - $this->addSql('ALTER TABLE chill_person_closingmotive DROP ordering'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20200422125935.php b/src/Bundle/ChillPersonBundle/migrations/Version20200422125935.php index 1921a0ddd..5ac4b96fb 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20200422125935.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20200422125935.php @@ -1,4 +1,13 @@ -addSql('DROP FUNCTION get_last_address(integer, date)'); - $this->addSql(<<<'SQL' -CREATE OR REPLACE FUNCTION public.get_last_address ( - pid integer, - before_date date) -RETURNS TABLE( - person_id integer, - address_id integer, - streetaddress1 varchar(255), - streetaddress2 varchar(255), - validfrom date, - postcode_label varchar(255), - postcode_code varchar(100), - postcode_id integer, - isnoaddress boolean, - country_name json, - country_code varchar(3), - country_id integer) - AS -$BODY$ -SELECT - pid AS person_id, - chill_main_address.id AS address_id, - chill_main_address.streetaddress1, - chill_main_address.streetaddress2, - chill_main_address.validfrom, - chill_main_postal_code.label, - chill_main_postal_code.code, - chill_main_postal_code.id AS postal_code_id, - chill_main_address.isnoaddress AS isnoaddress, - country.name, - country.countrycode, - country.id AS country_id -FROM chill_main_address -JOIN ( - SELECT - chill_main_address.id AS address_id, - validfrom, - rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos - FROM chill_person_persons_to_addresses - JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id - WHERE person_id = pid - AND chill_main_address.validfrom <= before_date -) AS ranking ON ranking.address_id = chill_main_address.id -JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id -JOIN country ON chill_main_postal_code.country_id = country.id -WHERE ranking.pos = 1 -$BODY$ -LANGUAGE sql VOLATILE -COST 100; -SQL - ); - - $this->addSql(<<<'SQL' -CREATE OR REPLACE FUNCTION get_last_address_isnoaddress ( - pid integer, - before_date date) -RETURNS BOOL AS -$BODY$ -SELECT isnoaddress FROM get_last_address(pid, before_date) -$BODY$ -LANGUAGE sql volatile -COST 100; -SQL - ); - - } - public function down(Schema $schema): void { $this->addSql('DROP FUNCTION public.get_last_address_isnoaddress(integer, date);'); $this->addSql('DROP FUNCTION get_last_address(integer, date)'); - $this->addSql(<<<'SQL' -CREATE OR REPLACE FUNCTION public.get_last_address ( - pid integer, - before_date date) -RETURNS TABLE( - person_id integer, - address_id integer, - streetaddress1 varchar(255), - streetaddress2 varchar(255), - validfrom date, - postcode_label varchar(255), - postcode_code varchar(100), - postcode_id integer, - country_name json, - country_code varchar(3), - country_id integer) - AS -$BODY$ -SELECT - pid AS person_id, - chill_main_address.id AS address_id, - chill_main_address.streetaddress1, - chill_main_address.streetaddress2, - chill_main_address.validfrom, - chill_main_postal_code.label, - chill_main_postal_code.code, - chill_main_postal_code.id AS postal_code_id, - country.name, - country.countrycode, - country.id AS country_id -FROM chill_main_address -JOIN ( - SELECT - chill_main_address.id AS address_id, - validfrom, - rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos - FROM chill_person_persons_to_addresses - JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id - WHERE person_id = pid - AND chill_main_address.validfrom <= before_date -) AS ranking ON ranking.address_id = chill_main_address.id -JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id -JOIN country ON chill_main_postal_code.country_id = country.id -WHERE ranking.pos = 1 -$BODY$ -LANGUAGE sql VOLATILE -COST 100; -SQL + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION public.get_last_address ( + pid integer, + before_date date) + RETURNS TABLE( + person_id integer, + address_id integer, + streetaddress1 varchar(255), + streetaddress2 varchar(255), + validfrom date, + postcode_label varchar(255), + postcode_code varchar(100), + postcode_id integer, + country_name json, + country_code varchar(3), + country_id integer) + AS + $BODY$ + SELECT + pid AS person_id, + chill_main_address.id AS address_id, + chill_main_address.streetaddress1, + chill_main_address.streetaddress2, + chill_main_address.validfrom, + chill_main_postal_code.label, + chill_main_postal_code.code, + chill_main_postal_code.id AS postal_code_id, + country.name, + country.countrycode, + country.id AS country_id + FROM chill_main_address + JOIN ( + SELECT + chill_main_address.id AS address_id, + validfrom, + rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos + FROM chill_person_persons_to_addresses + JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id + WHERE person_id = pid + AND chill_main_address.validfrom <= before_date + ) AS ranking ON ranking.address_id = chill_main_address.id + JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id + JOIN country ON chill_main_postal_code.country_id = country.id + WHERE ranking.pos = 1 + $BODY$ + LANGUAGE sql VOLATILE + COST 100; + SQL + ); + } + + public function up(Schema $schema): void + { + $this->addSql('DROP FUNCTION get_last_address(integer, date)'); + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION public.get_last_address ( + pid integer, + before_date date) + RETURNS TABLE( + person_id integer, + address_id integer, + streetaddress1 varchar(255), + streetaddress2 varchar(255), + validfrom date, + postcode_label varchar(255), + postcode_code varchar(100), + postcode_id integer, + isnoaddress boolean, + country_name json, + country_code varchar(3), + country_id integer) + AS + $BODY$ + SELECT + pid AS person_id, + chill_main_address.id AS address_id, + chill_main_address.streetaddress1, + chill_main_address.streetaddress2, + chill_main_address.validfrom, + chill_main_postal_code.label, + chill_main_postal_code.code, + chill_main_postal_code.id AS postal_code_id, + chill_main_address.isnoaddress AS isnoaddress, + country.name, + country.countrycode, + country.id AS country_id + FROM chill_main_address + JOIN ( + SELECT + chill_main_address.id AS address_id, + validfrom, + rank() OVER (PARTITION BY person_id ORDER BY validfrom DESC) as pos + FROM chill_person_persons_to_addresses + JOIN chill_main_address ON chill_person_persons_to_addresses.address_id = chill_main_address.id + WHERE person_id = pid + AND chill_main_address.validfrom <= before_date + ) AS ranking ON ranking.address_id = chill_main_address.id + JOIN chill_main_postal_code ON chill_main_address.postcode_id = chill_main_postal_code.id + JOIN country ON chill_main_postal_code.country_id = country.id + WHERE ranking.pos = 1 + $BODY$ + LANGUAGE sql VOLATILE + COST 100; + SQL ); + $this->addSql( + <<<'SQL' + CREATE OR REPLACE FUNCTION get_last_address_isnoaddress ( + pid integer, + before_date date) + RETURNS BOOL AS + $BODY$ + SELECT isnoaddress FROM get_last_address(pid, before_date) + $BODY$ + LANGUAGE sql volatile + COST 100; + SQL + ); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210128152747.php b/src/Bundle/ChillPersonBundle/migrations/Version20210128152747.php index 120be0800..995625359 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210128152747.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210128152747.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_person_not_duplicate_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_not_duplicate'); + } + + public function getDescription(): string { return ''; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SEQUENCE chill_person_not_duplicate_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); @@ -29,11 +43,4 @@ final class Version20210128152747 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_not_duplicate ADD CONSTRAINT FK_BD211EE22C402DF5 FOREIGN KEY (person2_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_not_duplicate ADD CONSTRAINT FK_BD211EE2A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('DROP SEQUENCE chill_person_not_duplicate_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_not_duplicate'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php b/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php index 3258bd351..2f52f9d00 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210318095831.php @@ -1,5 +1,12 @@ addSql('DROP SEQUENCE chill_person_phone_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_phone'); + } + + public function getDescription(): string { return ''; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -26,11 +40,4 @@ final class Version20210318095831 extends AbstractMigration $this->addSql('CREATE INDEX IDX_72C1F87217BBB47 ON chill_person_phone (person_id)'); $this->addSql('ALTER TABLE chill_person_phone ADD CONSTRAINT FK_72C1F87217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('DROP SEQUENCE chill_person_phone_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_phone'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php b/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php index 6e2f105df..d0a14caa4 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210325141540.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_phone ADD type TEXT DEFAULT NULL'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your need $this->addSql('ALTER TABLE chill_person_phone DROP type'); } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE chill_person_phone ADD type TEXT DEFAULT NULL'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php b/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php index 8ae60b739..b947963f0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210326113045.php @@ -1,5 +1,12 @@ addSql('CREATE TABLE persons_accompanying_periods (person_id INT NOT NULL, accompanyingperiod_id INT NOT NULL, PRIMARY KEY(person_id, accompanyingperiod_id))'); - $this->addSql('CREATE INDEX IDX_49A3871F217BBB47 ON persons_accompanying_periods (person_id)'); - $this->addSql('CREATE INDEX IDX_49A3871F550B0C53 ON persons_accompanying_periods (accompanyingperiod_id)'); - $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); - - // insert datas in new join table - $this->addSql('INSERT INTO persons_accompanying_periods (person_id, accompanyingperiod_id) ' - . 'SELECT person_id, id as accompagnying_period_id FROM chill_person_accompanying_period WHERE person_id IS NOT NULL'); - - // drop column - $this->addSql('DROP INDEX idx_64a4a621217bbb47'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT fk_64a4a621217bbb47'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP person_id'); - } - + /** * The distinct clause makes that for each group of duplicates, it keeps only the first row in the returned result set. - * Then we have only few lost datas. Lost datas: when many persons for one AccompanyingPeriod (keep only first person) + * Then we have only few lost datas. Lost datas: when many persons for one AccompanyingPeriod (keep only first person). */ - public function down(Schema $schema) : void + public function down(Schema $schema): void { // add column $this->addSql('ALTER TABLE chill_person_accompanying_period ADD person_id INT DEFAULT NULL'); @@ -59,12 +37,39 @@ final class Version20210326113045 extends AbstractMigration $this->addSql('UPDATE chill_person_accompanying_period AS ap ' . 'SET person_id = jt.person_id ' . 'FROM ( ' - . 'SELECT DISTINCT ON (accompanyingperiod_id) accompanyingperiod_id AS id, person_id FROM persons_accompanying_periods ' - . 'ORDER BY id, person_id ASC ' + . 'SELECT DISTINCT ON (accompanyingperiod_id) accompanyingperiod_id AS id, person_id FROM persons_accompanying_periods ' + . 'ORDER BY id, person_id ASC ' . ') AS jt ' . 'WHERE ap.id = jt.id'); - + // drop join table $this->addSql('DROP TABLE persons_accompanying_periods'); } + + public function getDescription(): string + { + return 'Change model relation between Person and AccompagnyingPeriod, without losing datas when going up'; + } + + /** + * In these direction, there is no loss. + */ + public function up(Schema $schema): void + { + // create join table + $this->addSql('CREATE TABLE persons_accompanying_periods (person_id INT NOT NULL, accompanyingperiod_id INT NOT NULL, PRIMARY KEY(person_id, accompanyingperiod_id))'); + $this->addSql('CREATE INDEX IDX_49A3871F217BBB47 ON persons_accompanying_periods (person_id)'); + $this->addSql('CREATE INDEX IDX_49A3871F550B0C53 ON persons_accompanying_periods (accompanyingperiod_id)'); + $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT FK_49A3871F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); + + // insert datas in new join table + $this->addSql('INSERT INTO persons_accompanying_periods (person_id, accompanyingperiod_id) ' + . 'SELECT person_id, id as accompagnying_period_id FROM chill_person_accompanying_period WHERE person_id IS NOT NULL'); + + // drop column + $this->addSql('DROP INDEX idx_64a4a621217bbb47'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT fk_64a4a621217bbb47'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP person_id'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php index 1ccab6a50..7cc589e12 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329090904.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A86856A273CC'); + + $this->addSql('DROP SEQUENCE chill_person_accompanying_period_origin_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_accompanying_period_origin'); + + $this->addSql('DROP INDEX IDX_E260A86856A273CC'); + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP origin_id'); + } + + public function getDescription(): string { return 'Add AccompanyingPeriod Origin table'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_origin_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_person_accompanying_period_origin (id INT NOT NULL, label VARCHAR(255) NOT NULL, noActiveAfter DATE DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_origin.noActiveAfter IS \'(DC2Type:date_immutable)\''); - + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD origin_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86856A273CC FOREIGN KEY (origin_id) REFERENCES chill_person_accompanying_period_origin (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_E260A86856A273CC ON chill_person_accompanying_period (origin_id)'); - - } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A86856A273CC'); - - $this->addSql('DROP SEQUENCE chill_person_accompanying_period_origin_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_accompanying_period_origin'); - - $this->addSql('DROP INDEX IDX_E260A86856A273CC'); - $this->addSql('ALTER TABLE chill_person_accompanying_period DROP origin_id'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php index 2cba2dd7e..062c7fd17 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329113152.php @@ -1,5 +1,12 @@ addSql('CREATE SEQUENCE chill_person_accompanying_period_comment_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE chill_person_accompanying_period_comment (id INT NOT NULL, creator_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, content TEXT NOT NULL, accompanyingPeriod_id INT NOT NULL, updatedBy_id INT NOT NULL, PRIMARY KEY(id))'); - - $this->addSql('CREATE INDEX IDX_CD960EF3D7FA8EF0 ON chill_person_accompanying_period_comment (accompanyingPeriod_id)'); - $this->addSql('CREATE INDEX IDX_CD960EF361220EA6 ON chill_person_accompanying_period_comment (creator_id)'); - $this->addSql('CREATE INDEX IDX_CD960EF365FF1AEC ON chill_person_accompanying_period_comment (updatedBy_id)'); - - $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF361220EA6 FOREIGN KEY (creator_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF365FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - - $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_resource_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE chill_person_accompanying_period_resource (id INT NOT NULL, person_id INT DEFAULT NULL, comment_id INT DEFAULT NULL, accompanyingPeriod_id INT NOT NULL, thirdParty_id INT DEFAULT NULL, PRIMARY KEY(id))'); - - $this->addSql('CREATE INDEX IDX_DC78989FD7FA8EF0 ON chill_person_accompanying_period_resource (accompanyingPeriod_id)'); - $this->addSql('CREATE INDEX IDX_DC78989F3EA5CAB0 ON chill_person_accompanying_period_resource (thirdParty_id)'); - $this->addSql('CREATE INDEX IDX_DC78989F217BBB47 ON chill_person_accompanying_period_resource (person_id)'); - $this->addSql('CREATE INDEX IDX_DC78989FF8697D13 ON chill_person_accompanying_period_resource (comment_id)'); - - $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F3EA5CAB0 FOREIGN KEY (thirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FF8697D13 FOREIGN KEY (comment_id) REFERENCES chill_person_accompanying_period_comment (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('DROP SEQUENCE chill_person_accompanying_period_resource_id_seq CASCADE'); $this->addSql('DROP TABLE chill_person_accompanying_period_resource'); $this->addSql('DROP SEQUENCE chill_person_accompanying_period_comment_id_seq CASCADE'); $this->addSql('DROP TABLE chill_person_accompanying_period_comment'); - + } + + public function getDescription(): string + { + return 'Add AccompanyingPeriod Comment and Resource tables'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_comment_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_person_accompanying_period_comment (id INT NOT NULL, creator_id INT NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, content TEXT NOT NULL, accompanyingPeriod_id INT NOT NULL, updatedBy_id INT NOT NULL, PRIMARY KEY(id))'); + + $this->addSql('CREATE INDEX IDX_CD960EF3D7FA8EF0 ON chill_person_accompanying_period_comment (accompanyingPeriod_id)'); + $this->addSql('CREATE INDEX IDX_CD960EF361220EA6 ON chill_person_accompanying_period_comment (creator_id)'); + $this->addSql('CREATE INDEX IDX_CD960EF365FF1AEC ON chill_person_accompanying_period_comment (updatedBy_id)'); + + $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF3D7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF361220EA6 FOREIGN KEY (creator_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_comment ADD CONSTRAINT FK_CD960EF365FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + + $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_resource_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE chill_person_accompanying_period_resource (id INT NOT NULL, person_id INT DEFAULT NULL, comment_id INT DEFAULT NULL, accompanyingPeriod_id INT NOT NULL, thirdParty_id INT DEFAULT NULL, PRIMARY KEY(id))'); + + $this->addSql('CREATE INDEX IDX_DC78989FD7FA8EF0 ON chill_person_accompanying_period_resource (accompanyingPeriod_id)'); + $this->addSql('CREATE INDEX IDX_DC78989F3EA5CAB0 ON chill_person_accompanying_period_resource (thirdParty_id)'); + $this->addSql('CREATE INDEX IDX_DC78989F217BBB47 ON chill_person_accompanying_period_resource (person_id)'); + $this->addSql('CREATE INDEX IDX_DC78989FF8697D13 ON chill_person_accompanying_period_resource (comment_id)'); + + $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FD7FA8EF0 FOREIGN KEY (accompanyingPeriod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F3EA5CAB0 FOREIGN KEY (thirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_resource ADD CONSTRAINT FK_DC78989FF8697D13 FOREIGN KEY (comment_id) REFERENCES chill_person_accompanying_period_comment (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php b/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php index dc75997ab..34111e6c1 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210329144338.php @@ -1,5 +1,12 @@ addSql('CREATE TABLE accompanying_periods_scopes (accompanying_period_id INT NOT NULL, scope_id INT NOT NULL, PRIMARY KEY(accompanying_period_id, scope_id))'); - - $this->addSql('CREATE INDEX IDX_87C4EAB032A7A428 ON accompanying_periods_scopes (accompanying_period_id)'); - $this->addSql('CREATE INDEX IDX_87C4EAB0682B5931 ON accompanying_periods_scopes (scope_id)'); - - $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB032A7A428 FOREIGN KEY (accompanying_period_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB0682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD step VARCHAR(32) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD intensity VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD createdBy_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorPerson_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorThirdParty_id INT DEFAULT NULL'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorAnonymous BOOLEAN NOT NULL DEFAULT \'false\''); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD emergency BOOLEAN NOT NULL DEFAULT \'false\''); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD confidential BOOLEAN NOT NULL DEFAULT \'false\''); - - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A8683174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86834269C3F FOREIGN KEY (requestorPerson_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A868CFE4D554 FOREIGN KEY (requestorThirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - $this->addSql('CREATE INDEX IDX_E260A8683174800F ON chill_person_accompanying_period (createdBy_id)'); - $this->addSql('CREATE INDEX IDX_E260A86834269C3F ON chill_person_accompanying_period (requestorPerson_id)'); - $this->addSql('CREATE INDEX IDX_E260A868CFE4D554 ON chill_person_accompanying_period (requestorThirdParty_id)'); - - } - - public function down(Schema $schema) : void - { - $this->addSql('DROP TABLE accompanying_periods_scopes'); - + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A8683174800F'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A86834269C3F'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP CONSTRAINT FK_E260A868CFE4D554'); - + $this->addSql('DROP INDEX IDX_E260A8683174800F'); $this->addSql('DROP INDEX IDX_E260A86834269C3F'); $this->addSql('DROP INDEX IDX_E260A868CFE4D554'); - + $this->addSql('ALTER TABLE chill_person_accompanying_period DROP step'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP intensity'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP createdBy_id'); @@ -69,6 +39,38 @@ final class Version20210329144338 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period DROP requestorAnonymous'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP emergency'); $this->addSql('ALTER TABLE chill_person_accompanying_period DROP confidential'); - + } + + public function getDescription(): string + { + return 'Complete AccompanyingPeriod table'; + } + + public function up(Schema $schema): void + { + $this->addSql('CREATE TABLE accompanying_periods_scopes (accompanying_period_id INT NOT NULL, scope_id INT NOT NULL, PRIMARY KEY(accompanying_period_id, scope_id))'); + + $this->addSql('CREATE INDEX IDX_87C4EAB032A7A428 ON accompanying_periods_scopes (accompanying_period_id)'); + $this->addSql('CREATE INDEX IDX_87C4EAB0682B5931 ON accompanying_periods_scopes (scope_id)'); + + $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB032A7A428 FOREIGN KEY (accompanying_period_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE accompanying_periods_scopes ADD CONSTRAINT FK_87C4EAB0682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD step VARCHAR(32) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD intensity VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD createdBy_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorPerson_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorThirdParty_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD requestorAnonymous BOOLEAN NOT NULL DEFAULT \'false\''); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD emergency BOOLEAN NOT NULL DEFAULT \'false\''); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD confidential BOOLEAN NOT NULL DEFAULT \'false\''); + + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A8683174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A86834269C3F FOREIGN KEY (requestorPerson_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period ADD CONSTRAINT FK_E260A868CFE4D554 FOREIGN KEY (requestorThirdParty_id) REFERENCES chill_3party.third_party (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + + $this->addSql('CREATE INDEX IDX_E260A8683174800F ON chill_person_accompanying_period (createdBy_id)'); + $this->addSql('CREATE INDEX IDX_E260A86834269C3F ON chill_person_accompanying_period (requestorPerson_id)'); + $this->addSql('CREATE INDEX IDX_E260A868CFE4D554 ON chill_person_accompanying_period (requestorThirdParty_id)'); } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php b/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php index 681132565..6e2c80107 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210330164922.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_closingmotive RENAME TO chill_person_accompanying_period_closingmotive'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive RENAME CONSTRAINT fk_92351ece727aca70 TO FK_72D110E8727ACA70'); - $this->addSql('ALTER TABLE chill_person_accompanying_period RENAME CONSTRAINT fk_64a4a621504cb38d TO FK_E260A868504CB38D'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive RENAME TO chill_person_closingmotive'); $this->addSql('ALTER TABLE chill_person_closingmotive RENAME CONSTRAINT FK_72D110E8727ACA70 TO fk_92351ece727aca70'); $this->addSql('ALTER TABLE chill_person_accompanying_period RENAME CONSTRAINT FK_E260A868504CB38D TO fk_64a4a621504cb38d'); } + + public function getDescription(): string + { + return 'Rename table closinmotive'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_closingmotive RENAME TO chill_person_accompanying_period_closingmotive'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive RENAME CONSTRAINT fk_92351ece727aca70 TO FK_72D110E8727ACA70'); + $this->addSql('ALTER TABLE chill_person_accompanying_period RENAME CONSTRAINT fk_64a4a621504cb38d TO FK_E260A868504CB38D'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php index 9c379c4b0..7ba75efa9 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210331084527.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE persons_accompanying_periods DROP CONSTRAINT persons_accompanying_periods_pkey'); - $this->addSql('ALTER TABLE persons_accompanying_periods RENAME TO chill_person_accompanying_period_participation'); - - // 2 - // SERIAL automatically create sequence with NEXTVAL() - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD COLUMN id SERIAL NOT NULL PRIMARY KEY'); - // drop NEXTVAL() in column definition - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ALTER id DROP DEFAULT'); - - // 3 - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD startDate DATE NOT NULL DEFAULT \'1970-01-01\''); - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD endDate DATE DEFAULT NULL'); - - // 4 - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f217bbb47'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f550b0c53'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - $this->addSql('ALTER INDEX idx_49a3871f217bbb47 RENAME TO IDX_A59DF89F217BBB47'); - $this->addSql('ALTER INDEX idx_49a3871f550b0c53 RENAME TO IDX_A59DF89F550B0C53'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // 4 $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT FK_A59DF89F217BBB47'); @@ -51,17 +28,47 @@ final class Version20210331084527 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT fk_49a3871f550b0c53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER INDEX idx_a59df89f550b0c53 RENAME TO idx_49a3871f550b0c53'); $this->addSql('ALTER INDEX idx_a59df89f217bbb47 RENAME TO idx_49a3871f217bbb47'); - + // 3 $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP startDate'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP endDate'); - + // 2 $this->addSql('DROP SEQUENCE chill_person_accompanying_period_participation_id_seq CASCADE'); $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP id'); - + // 1 $this->addSql('ALTER TABLE chill_person_accompanying_period_participation RENAME TO persons_accompanying_periods'); $this->addSql('ALTER TABLE persons_accompanying_periods ADD CONSTRAINT persons_accompanying_periods_pkey PRIMARY KEY (person_id, accompanyingperiod_id)'); } + + public function getDescription(): string + { + return 'Transform join table between Person and AccompanyingPeriod in Doctrine entity'; + } + + public function up(Schema $schema): void + { + // 1 + $this->addSql('ALTER TABLE persons_accompanying_periods DROP CONSTRAINT persons_accompanying_periods_pkey'); + $this->addSql('ALTER TABLE persons_accompanying_periods RENAME TO chill_person_accompanying_period_participation'); + + // 2 + // SERIAL automatically create sequence with NEXTVAL() + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD COLUMN id SERIAL NOT NULL PRIMARY KEY'); + // drop NEXTVAL() in column definition + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ALTER id DROP DEFAULT'); + + // 3 + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD startDate DATE NOT NULL DEFAULT \'1970-01-01\''); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD endDate DATE DEFAULT NULL'); + + // 4 + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f217bbb47'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation DROP CONSTRAINT fk_49a3871f550b0c53'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_participation ADD CONSTRAINT FK_A59DF89F550B0C53 FOREIGN KEY (accompanyingperiod_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER INDEX idx_49a3871f217bbb47 RENAME TO IDX_A59DF89F217BBB47'); + $this->addSql('ALTER INDEX idx_49a3871f550b0c53 RENAME TO IDX_A59DF89F550B0C53'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210419105054.php b/src/Bundle/ChillPersonBundle/migrations/Version20210419105054.php index c2b752822..c340ab989 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210419105054.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210419105054.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_closingmotive_id_seq RENAME TO ' - . 'chill_person_accompanying_period_closingmotive_id_seq'); - - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { $this->addSql('ALTER TABLE chill_person_accompanying_period_closingmotive_id_seq ' . 'RENAME TO chill_person_closingmotive_id_seq'); } + + public function getDescription(): string + { + return 'rename sequence "closing motive"'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_closingmotive_id_seq RENAME TO ' + . 'chill_person_accompanying_period_closingmotive_id_seq'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210419105940.php b/src/Bundle/ChillPersonBundle/migrations/Version20210419105940.php index 4214c7069..2ef445f32 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210419105940.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210419105940.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_origin ' - . 'ALTER label TYPE JSON USING json_build_object(\'fr\', label)::jsonb'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_origin ' - . 'ALTER label DROP DEFAULT'); - } - - public function down(Schema $schema) : void + public function down(Schema $schema): void { // this will keep the '"' at first and last character, but is acceptable $this->addSql('ALTER TABLE chill_person_accompanying_period_origin ' @@ -33,4 +27,17 @@ final class Version20210419105940 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_origin ' . 'ALTER label DROP DEFAULT'); } + + public function getDescription(): string + { + return 'set label for origin as json'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_person_accompanying_period_origin ' + . 'ALTER label TYPE JSON USING json_build_object(\'fr\', label)::jsonb'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_origin ' + . 'ALTER label DROP DEFAULT'); + } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210419112619.php b/src/Bundle/ChillPersonBundle/migrations/Version20210419112619.php index 919fe4cff..1fe9b2b4e 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210419112619.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210419112619.php @@ -1,5 +1,12 @@ addSql('COMMENT ON COLUMN chill_person_accompanying_period_closingmotive.name IS \'(DC2Type:json_array)\''); + } + + public function getDescription(): string { return 'fix deprecated json_array'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_closingmotive.name IS NULL'); } - - public function down(Schema $schema) : void - { - $this->addSql('COMMENT ON COLUMN chill_person_accompanying_period_closingmotive.name IS \'(DC2Type:json_array)\''); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210426145930.php b/src/Bundle/ChillPersonBundle/migrations/Version20210426145930.php index 177633433..23dc6e9ec 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210426145930.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210426145930.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_social_action DROP CONSTRAINT FK_B7ABFAB8727ACA70'); + $this->addSql('ALTER TABLE chill_person_social_action_goal DROP CONSTRAINT FK_163CA4DD3DC32179'); + $this->addSql('ALTER TABLE chill_person_social_action_result DROP CONSTRAINT FK_CA98C58C3DC32179'); + $this->addSql('ALTER TABLE chill_person_social_action DROP CONSTRAINT FK_B7ABFAB85E7AA58C'); + $this->addSql('ALTER TABLE chill_person_social_issue DROP CONSTRAINT FK_7A484DAE727ACA70'); + $this->addSql('ALTER TABLE chill_person_social_action_goal DROP CONSTRAINT FK_163CA4DD667D1AFE'); + $this->addSql('ALTER TABLE chill_person_social_work_goal_result DROP CONSTRAINT FK_F3BAEEA9667D1AFE'); + $this->addSql('ALTER TABLE chill_person_social_action_result DROP CONSTRAINT FK_CA98C58C7A7B643'); + $this->addSql('ALTER TABLE chill_person_social_work_goal_result DROP CONSTRAINT FK_F3BAEEA97A7B643'); + $this->addSql('DROP SEQUENCE chill_person_social_action_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_social_issue_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_social_work_goal_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_social_work_result_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_social_action'); + $this->addSql('DROP TABLE chill_person_social_action_goal'); + $this->addSql('DROP TABLE chill_person_social_action_result'); + $this->addSql('DROP TABLE chill_person_social_issue'); + $this->addSql('DROP TABLE chill_person_social_work_goal'); + $this->addSql('DROP TABLE chill_person_social_work_goal_result'); + $this->addSql('DROP TABLE chill_person_social_work_result'); + } + + public function getDescription(): string { return 'Create Social action, Social Issue, Work Goal and Work Result'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE SEQUENCE chill_person_social_action_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE chill_person_social_issue_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); @@ -50,28 +81,4 @@ final class Version20210426145930 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_social_work_goal_result ADD CONSTRAINT FK_F3BAEEA9667D1AFE FOREIGN KEY (goal_id) REFERENCES chill_person_social_work_goal (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_social_work_goal_result ADD CONSTRAINT FK_F3BAEEA97A7B643 FOREIGN KEY (result_id) REFERENCES chill_person_social_work_result (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE chill_person_social_action DROP CONSTRAINT FK_B7ABFAB8727ACA70'); - $this->addSql('ALTER TABLE chill_person_social_action_goal DROP CONSTRAINT FK_163CA4DD3DC32179'); - $this->addSql('ALTER TABLE chill_person_social_action_result DROP CONSTRAINT FK_CA98C58C3DC32179'); - $this->addSql('ALTER TABLE chill_person_social_action DROP CONSTRAINT FK_B7ABFAB85E7AA58C'); - $this->addSql('ALTER TABLE chill_person_social_issue DROP CONSTRAINT FK_7A484DAE727ACA70'); - $this->addSql('ALTER TABLE chill_person_social_action_goal DROP CONSTRAINT FK_163CA4DD667D1AFE'); - $this->addSql('ALTER TABLE chill_person_social_work_goal_result DROP CONSTRAINT FK_F3BAEEA9667D1AFE'); - $this->addSql('ALTER TABLE chill_person_social_action_result DROP CONSTRAINT FK_CA98C58C7A7B643'); - $this->addSql('ALTER TABLE chill_person_social_work_goal_result DROP CONSTRAINT FK_F3BAEEA97A7B643'); - $this->addSql('DROP SEQUENCE chill_person_social_action_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_social_issue_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_social_work_goal_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_social_work_result_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_social_action'); - $this->addSql('DROP TABLE chill_person_social_action_goal'); - $this->addSql('DROP TABLE chill_person_social_action_result'); - $this->addSql('DROP TABLE chill_person_social_issue'); - $this->addSql('DROP TABLE chill_person_social_work_goal'); - $this->addSql('DROP TABLE chill_person_social_work_goal_result'); - $this->addSql('DROP TABLE chill_person_social_work_result'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210427125700.php b/src/Bundle/ChillPersonBundle/migrations/Version20210427125700.php index 853d0b763..7da2d67d0 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210427125700.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210427125700.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE chill_person_accompanying_period_work_result DROP CONSTRAINT FK_46E95929B99F6060'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_third_party DROP CONSTRAINT FK_83B57B86B99F6060'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_goal DROP CONSTRAINT FK_911B88FEC55C1209'); + $this->addSql('ALTER TABLE chill_person_accompanying_period_work_goal_result DROP CONSTRAINT FK_3E37D1F37B14AD03'); + $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_goal_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE chill_person_social_work_evaluation_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_result'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_third_party'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_goal'); + $this->addSql('DROP TABLE chill_person_accompanying_period_work_goal_result'); + $this->addSql('DROP TABLE chill_person_social_work_evaluation'); + } + + public function getDescription(): string { return 'Create tables for the entites AccomanyingPeriodWork, AccomanyingPeriodWorkGoal & Social/WorkEvaluation'; } - public function up(Schema $schema) : void + public function up(Schema $schema): void { $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_work_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE chill_person_accompanying_period_work_goal_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); @@ -57,21 +81,4 @@ final class Version20210427125700 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_accompanying_period_work_goal_result ADD CONSTRAINT FK_3E37D1F37A7B643 FOREIGN KEY (result_id) REFERENCES chill_person_social_work_result (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_social_work_evaluation ADD CONSTRAINT FK_2E23F3FEBF32A3DA FOREIGN KEY (socialAction_id) REFERENCES chill_person_social_action (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema) : void - { - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_result DROP CONSTRAINT FK_46E95929B99F6060'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_third_party DROP CONSTRAINT FK_83B57B86B99F6060'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_goal DROP CONSTRAINT FK_911B88FEC55C1209'); - $this->addSql('ALTER TABLE chill_person_accompanying_period_work_goal_result DROP CONSTRAINT FK_3E37D1F37B14AD03'); - $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_accompanying_period_work_goal_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE chill_person_social_work_evaluation_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_result'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_third_party'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_goal'); - $this->addSql('DROP TABLE chill_person_accompanying_period_work_goal_result'); - $this->addSql('DROP TABLE chill_person_social_work_evaluation'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210505093408.php b/src/Bundle/ChillPersonBundle/migrations/Version20210505093408.php index cf5a93164..d79b31e3c 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210505093408.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210505093408.php @@ -1,5 +1,12 @@ addSql('ALTER TABLE HouseholdMembers DROP CONSTRAINT FK_4D1FB288E79FF843'); + $this->addSql('ALTER TABLE HouseholdMembers DROP CONSTRAINT FK_4D1FB288217BBB47'); + $this->addSql('DROP SEQUENCE Household_id_seq CASCADE'); + $this->addSql('DROP SEQUENCE HouseholdMembers_id_seq CASCADE'); + $this->addSql('DROP TABLE Household'); + $this->addSql('DROP TABLE HouseholdMembers'); + } + public function getDescription(): string { return 'Create Household and HouseholdMembers tables'; @@ -28,14 +45,4 @@ final class Version20210505093408 extends AbstractMigration $this->addSql('ALTER TABLE HouseholdMembers ADD CONSTRAINT FK_4D1FB288217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE HouseholdMembers ADD CONSTRAINT FK_4D1FB288E79FF843 FOREIGN KEY (household_id) REFERENCES Household (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE HouseholdMembers DROP CONSTRAINT FK_4D1FB288E79FF843'); - $this->addSql('ALTER TABLE HouseholdMembers DROP CONSTRAINT FK_4D1FB288217BBB47'); - $this->addSql('DROP SEQUENCE Household_id_seq CASCADE'); - $this->addSql('DROP SEQUENCE HouseholdMembers_id_seq CASCADE'); - $this->addSql('DROP TABLE Household'); - $this->addSql('DROP TABLE HouseholdMembers'); - } } diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20210505154316.php b/src/Bundle/ChillPersonBundle/migrations/Version20210505154316.php index bb3a56337..cddb987bf 100644 --- a/src/Bundle/ChillPersonBundle/migrations/Version20210505154316.php +++ b/src/Bundle/ChillPersonBundle/migrations/Version20210505154316.php @@ -1,5 +1,12 @@ addSql('DROP TABLE chill_person_household_to_addresses'); + } + public function getDescription(): string { return 'Add a household_to_addresses table'; @@ -25,9 +37,4 @@ final class Version20210505154316 extends AbstractMigration $this->addSql('ALTER TABLE chill_person_household_to_addresses ADD CONSTRAINT FK_7109483E79FF843 FOREIGN KEY (household_id) REFERENCES Household (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_person_household_to_addresses ADD CONSTRAINT FK_7109483F5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->addSql('DROP TABLE chill_person_household_to_addresses'); - } } diff --git a/src/Bundle/ChillReportBundle/ChillReportBundle.php b/src/Bundle/ChillReportBundle/ChillReportBundle.php index 967796d8b..b0e75c8c4 100644 --- a/src/Bundle/ChillReportBundle/ChillReportBundle.php +++ b/src/Bundle/ChillReportBundle/ChillReportBundle.php @@ -1,5 +1,12 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Controller; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\PersonBundle\Privacy\PrivacyEvent; -use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Form\Extension\Core\Type\FormType; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Privacy\PrivacyEvent; use Chill\ReportBundle\Entity\Report; use Chill\ReportBundle\Form\ReportType; - +use DateTime; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Role\Role; /** - * Class ReportController - * - * @package Chill\ReportBundle\Controller + * Class ReportController. */ class ReportController extends AbstractController { - /** - * @var EventDispatcherInterface - */ - protected $eventDispatcher; - /** * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var EventDispatcherInterface + */ + protected $eventDispatcher; + /** * @var PaginatorFactory */ protected $paginator; - + /** * ReportController constructor. - * - * @param EventDispatcherInterface $eventDispatcher - * @param AuthorizationHelper $authorizationHelper - * @param PaginatorFactory $paginator */ public function __construct( EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper, PaginatorFactory $paginator - ) - { + ) { $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; $this->paginator = $paginator; } - - - /** - * List all the report entities for a given person. - * - * @param integer $person_id The id of the person. - * @param Request $request The request - * @return Response The web page. - */ - public function listAction($person_id, Request $request) - { - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - - $reachableScopes = $this->authorizationHelper - ->getReachableScopes($this->getUser(), new Role('CHILL_REPORT_SEE'), - $person->getCenter()); - - $total = $em - ->createQuery("SELECT COUNT(r.id) FROM ChillReportBundle:Report r " - . "WHERE r.person = :person AND r.scope IN (:scopes) ") - ->setParameter('person', $person) - ->setParameter('scopes', $reachableScopes) - ->getSingleScalarResult(); - - // get the PaginatorFactory - $paginator = $this->paginator->create($total); - - $reports = $em->createQuery('SELECT r - FROM ChillReportBundle:Report r - WHERE r.person = :person AND r.scope IN (:scopes) - ORDER BY r.date DESC') - ->setParameter('person', $person) - ->setParameter('scopes', $reachableScopes) - ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) - ->setMaxResults($paginator->getItemsPerPage()) - ->getResult() - ; - - $event = new PrivacyEvent($person, array( - 'element_class' => Report::class, - 'action' => 'list' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillReportBundle:Report:list.html.twig', array( - 'reports' => $reports, - 'person' => $person, - 'paginator' => $paginator - )); - } /** - * Display a form for selecting which type of report to add for a given person + * Create a new report for a given person and of a given type. * - * @param integer $person_id The id of the person. - * @param Request $request The request - * @return Response The web page. - */ - public function selectReportTypeAction($person_id, Request $request) - { - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person') - ->find($person_id); - - if ($person === NULL) { - throw $this->createNotFoundException('Person not found!'); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, 'access denied for person view'); - // check access on report creation for a dummy report - $this->denyAccessUnlessGranted('CHILL_REPORT_CREATE', - (new Report())->setPerson($person), 'access denied for report creation'); - - - $cFGroupId = $request->query->get('cFGroup'); - - if($cFGroupId) { - return $this->redirect( - $this->generateUrl('report_new', - array('person_id' => $person_id, 'cf_group_id' => $cFGroupId))); - } - - $cFGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->findByEntity('Chill\ReportBundle\Entity\Report'); - - if(count($cFGroups) === 1 ){ - return $this->redirect( - $this->generateUrl('report_new', - array('person_id' => $person_id, 'cf_group_id' => $cFGroups[0]->getId()))); - } - - $cFGroupsChoice = array(); - - foreach ($cFGroups as $cFGroup) { - $cFGroupsChoice[$cFGroup->getId()] = $cFGroup->getName($request->getLocale()); - } - - $form = $this->get('form.factory') - ->createNamedBuilder(null, FormType::class, null, array( - 'method' => 'GET', - 'csrf_protection' => false - )) - ->add('cFGroup', ChoiceType::class, array( - 'choices' => array_combine(array_values($cFGroupsChoice),array_keys($cFGroupsChoice)), - )) - ->getForm(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - return $this->render('ChillReportBundle:Report:select_report_type.html.twig', array( - 'form' => $form->createView(), - 'person' => $person - )); - } - - /** - * Display a form for selecting which type of report to export - * (a csv file with all the report of this type) - * - * @param Request $request The request - * @return Response The web page. - */ - public function selectReportTypeForExportAction(Request $request) - { - $cFGroupId = $request->query->get('cFGroup'); - - if($cFGroupId) { - return $this->redirect( - $this->generateUrl('report_export_list', - array('cf_group_id' => $cFGroupId))); - } - - $em = $this->getDoctrine()->getManager(); - - $cFGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->findByEntity('Chill\ReportBundle\Entity\Report'); - - if(count($cFGroups) === 1 ){ - return $this->redirect( - $this->generateUrl('report_export_list', - array('cf_group_id' => $cFGroups[0]->getId()))); - } - - $cFGroupsChoice = array(); - - foreach ($cFGroups as $cFGroup) { - $cFGroupsChoice[$cFGroup->getId()] = $cFGroup->getName($request->getLocale()); - } - - $form = $this->get('form.factory') - ->createNamedBuilder(null, FormType::class, null, array( - 'method' => 'GET', - 'csrf_protection' => false - )) - ->add('cFGroup', ChoiceType::class, array( - 'choices' => array_combine(array_values($cFGroupsChoice),array_keys($cFGroupsChoice)), - )) - ->getForm(); - - return $this->render('ChillReportBundle:Report:select_report_type_for_export.html.twig', array( - 'form' => $form->createView(), - 'layout_name' => "@ChillMain/Export/layout.html.twig" - )); - } - - /** - * Return a csv file with all the reports of a given type - * - * @param integer $cf_group_id The id of the report type to export - * @param Request $request The request - * @return A csv file with all the reports of the selected type - */ - public function exportAction($cf_group_id, Request $request) - { - $em = $this->getDoctrine()->getManager(); - - $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($cf_group_id); - $reports = $em->getRepository('ChillReportBundle:Report')->findByCFGroup($cFGroup); - - - $response = $this->render('ChillReportBundle:Report:export.csv.twig', array( - 'reports' => $reports, - 'cf_group' => $cFGroup - )); - - $response->headers->set('Content-Type', 'text/csv; charset=utf-8'); - $response->headers->set('Content-Disposition', 'attachment; filename="export.csv"'); - return $response; - } - - /** - * Display a form for creating a new report for a given person and of a given type - * - * @param integer $person_id The id of the person. - * @param integer $cf_group_id The id of the report type. - * @param Request $request The request - * @return Response The web page. - */ - public function newAction($person_id, $cf_group_id, Request $request) - { - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - $cFGroup = $em - ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->find($cf_group_id); - - if ($person === NULL) { - throw $this->createNotFoundException("Person not found"); - } - - $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); - // check access on report creation for a dummy report - $this->denyAccessUnlessGranted('CHILL_REPORT_CREATE', - (new Report())->setPerson($person), 'access denied for report creation'); - - if ($cFGroup === NULL){ - throw $this->createNotFoundException("custom fields group not found"); - } - - $entity = new Report(); - $entity->setUser($this->get('security.token_storage')->getToken()->getUser()); - $entity->setDate(new \DateTime('now')); - - $entity->setCFGroup($cFGroup); - - $form = $this->createCreateForm($entity, $person, $cFGroup); - - return $this->render('ChillReportBundle:Report:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - 'person' => $person - )); - } - - /** - * Create a new report for a given person and of a given type - * - * @param integer $person_id The id of the person. - * @param integer $cf_group_id The id of the report type. + * @param int $person_id The id of the person. + * @param int $cf_group_id The id of the report type. * @param Request $request The request containing the form data (from the newAction) + * * @return Response The web page. */ public function createAction($person_id, $cf_group_id, Request $request) @@ -328,12 +72,12 @@ class ReportController extends AbstractController $entity = new Report(); $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->find($cf_group_id); + ->find($cf_group_id); $person = $em->getRepository('ChillPersonBundle:Person') - ->find($person_id); + ->find($person_id); - if($person === NULL || $cFGroup === NULL) { + if (null === $person || null === $cFGroup) { throw $this->createNotFoundException(); } @@ -353,94 +97,38 @@ class ReportController extends AbstractController $this->get('session') ->getFlashBag() - ->add('success', + ->add( + 'success', $this->get('translator') ->trans('Success : report created!') ); - return $this->redirect($this->generateUrl('report_view', - array('person_id' => $person_id,'report_id' => $entity->getId()))); + return $this->redirect($this->generateUrl( + 'report_view', + ['person_id' => $person_id, 'report_id' => $entity->getId()] + )); } - $this->get('session') - ->getFlashBag()->add('error', + ->getFlashBag()->add( + 'error', $this->get('translator') ->trans('The form is not valid. The report has not been created !') ); - return $this->render('ChillReportBundle:Report:new.html.twig', array( - 'entity' => $entity, - 'form' => $form->createView(), - 'person' => $person - )); - } - - /** - * Creates a form to create a Report entity. - * - * @param Report $entity The entity - * @param integer $person_id The id of the person. - * @param integer $cf_group_id The id of the report type. - * - * @return \Symfony\Component\Form\Form The form - */ - private function createCreateForm(Report $entity, Person $person, $cFGroup) - { - $form = $this->createForm(ReportType::class, $entity, array( - 'action' => $this->generateUrl('report_create', - array('person_id' => $person->getId(), - 'cf_group_id' => $cFGroup->getId())), - 'method' => 'POST', - 'cFGroup' => $cFGroup, - 'role' => new Role('CHILL_REPORT_CREATE'), - 'center' => $person->getCenter() - )); - - return $form; - } - - /** - * Find and display a report. - * - * @param integer $report_id The id of the report. - * @param integer $person_id The id of the person. - * @return Response The web page. - */ - public function viewAction($report_id, $person_id) - { - $em = $this->getDoctrine()->getManager(); - - $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); - - $entity = $em->getRepository('ChillReportBundle:Report')->find($report_id); - - if (!$entity || !$person) { - throw $this->createNotFoundException( - $this->get('translator')->trans('Unable to find this report.')); - } - - $this->denyAccessUnlessGranted('CHILL_REPORT_SEE', $entity); - - - $event = new PrivacyEvent($person, array( - 'element_class' => Report::class, - 'element_id' => $entity->getId(), - 'action' => 'view' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillReportBundle:Report:view.html.twig', array( + return $this->render('ChillReportBundle:Report:new.html.twig', [ 'entity' => $entity, + 'form' => $form->createView(), 'person' => $person, - )); + ]); } /** * Display a form to edit an existing Report entity. * - * @param integer $person_id The id of the person. - * @param integer $report_id The id of the report. + * @param int $person_id The id of the person. + * @param int $report_id The id of the report. + * * @return Response The web page. */ public function editAction($person_id, $report_id, Request $request) @@ -451,12 +139,15 @@ class ReportController extends AbstractController if (!$report) { throw $this->createNotFoundException( - $this->get('translator')->trans('Unable to find this report.')); + $this->get('translator')->trans('Unable to find this report.') + ); } - if(intval($person_id) !== intval($report->getPerson()->getId())) { - throw new \RuntimeException( - $this->get('translator')->trans('This is not the report of the person.'), 1); + if (intval($person_id) !== intval($report->getPerson()->getId())) { + throw new RuntimeException( + $this->get('translator')->trans('This is not the report of the person.'), + 1 + ); } $this->denyAccessUnlessGranted('CHILL_REPORT_UPDATE', $report); @@ -464,47 +155,288 @@ class ReportController extends AbstractController $person = $report->getPerson(); $editForm = $this->createEditForm($report); - - $event = new PrivacyEvent($person, array( + + $event = new PrivacyEvent($person, [ 'element_class' => Report::class, 'element_id' => $report->getId(), - 'action' => 'edit' - )); + 'action' => 'edit', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - return $this->render('ChillReportBundle:Report:edit.html.twig', array( - 'edit_form' => $editForm->createView(), + return $this->render('ChillReportBundle:Report:edit.html.twig', [ + 'edit_form' => $editForm->createView(), 'person' => $person, - )); + ]); } /** - * Creates a form to edit a Report entity. + * Return a csv file with all the reports of a given type. * - * @param Report $entity The report to edit. - * @param integer $person_id The id of the person. - * @return \Symfony\Component\Form\Form The form + * @param int $cf_group_id The id of the report type to export + * @param Request $request The request + * + * @return A csv file with all the reports of the selected type */ - private function createEditForm(Report $entity) + public function exportAction($cf_group_id, Request $request) { - $form = $this->createForm(ReportType::class, $entity, array( - 'action' => $this->generateUrl('report_update', - array('person_id' => $entity->getPerson()->getId(), - 'report_id' => $entity->getId())), - 'method' => 'PUT', - 'cFGroup' => $entity->getCFGroup(), - 'role' => new Role('CHILL_REPORT_UPDATE'), - 'center' => $entity->getPerson()->getCenter() - )); + $em = $this->getDoctrine()->getManager(); - return $form; + $cFGroup = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup')->find($cf_group_id); + $reports = $em->getRepository('ChillReportBundle:Report')->findByCFGroup($cFGroup); + + $response = $this->render('ChillReportBundle:Report:export.csv.twig', [ + 'reports' => $reports, + 'cf_group' => $cFGroup, + ]); + + $response->headers->set('Content-Type', 'text/csv; charset=utf-8'); + $response->headers->set('Content-Disposition', 'attachment; filename="export.csv"'); + + return $response; + } + + /** + * List all the report entities for a given person. + * + * @param int $person_id The id of the person. + * @param Request $request The request + * + * @return Response The web page. + */ + public function listAction($person_id, Request $request) + { + $em = $this->getDoctrine()->getManager(); + + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + + $reachableScopes = $this->authorizationHelper + ->getReachableScopes( + $this->getUser(), + new Role('CHILL_REPORT_SEE'), + $person->getCenter() + ); + + $total = $em + ->createQuery('SELECT COUNT(r.id) FROM ChillReportBundle:Report r ' + . 'WHERE r.person = :person AND r.scope IN (:scopes) ') + ->setParameter('person', $person) + ->setParameter('scopes', $reachableScopes) + ->getSingleScalarResult(); + + // get the PaginatorFactory + $paginator = $this->paginator->create($total); + + $reports = $em->createQuery('SELECT r + FROM ChillReportBundle:Report r + WHERE r.person = :person AND r.scope IN (:scopes) + ORDER BY r.date DESC') + ->setParameter('person', $person) + ->setParameter('scopes', $reachableScopes) + ->setFirstResult($paginator->getCurrentPage()->getFirstItemNumber()) + ->setMaxResults($paginator->getItemsPerPage()) + ->getResult(); + + $event = new PrivacyEvent($person, [ + 'element_class' => Report::class, + 'action' => 'list', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillReportBundle:Report:list.html.twig', [ + 'reports' => $reports, + 'person' => $person, + 'paginator' => $paginator, + ]); + } + + /** + * Display a form for creating a new report for a given person and of a given type. + * + * @param int $person_id The id of the person. + * @param int $cf_group_id The id of the report type. + * @param Request $request The request + * + * @return Response The web page. + */ + public function newAction($person_id, $cf_group_id, Request $request) + { + $em = $this->getDoctrine()->getManager(); + + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + $cFGroup = $em + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->find($cf_group_id); + + if (null === $person) { + throw $this->createNotFoundException('Person not found'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); + // check access on report creation for a dummy report + $this->denyAccessUnlessGranted( + 'CHILL_REPORT_CREATE', + (new Report())->setPerson($person), + 'access denied for report creation' + ); + + if (null === $cFGroup) { + throw $this->createNotFoundException('custom fields group not found'); + } + + $entity = new Report(); + $entity->setUser($this->get('security.token_storage')->getToken()->getUser()); + $entity->setDate(new DateTime('now')); + + $entity->setCFGroup($cFGroup); + + $form = $this->createCreateForm($entity, $person, $cFGroup); + + return $this->render('ChillReportBundle:Report:new.html.twig', [ + 'entity' => $entity, + 'form' => $form->createView(), + 'person' => $person, + ]); + } + + /** + * Display a form for selecting which type of report to add for a given person. + * + * @param int $person_id The id of the person. + * @param Request $request The request + * + * @return Response The web page. + */ + public function selectReportTypeAction($person_id, Request $request) + { + $em = $this->getDoctrine()->getManager(); + + $person = $em->getRepository('ChillPersonBundle:Person') + ->find($person_id); + + if (null === $person) { + throw $this->createNotFoundException('Person not found!'); + } + + $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person, 'access denied for person view'); + // check access on report creation for a dummy report + $this->denyAccessUnlessGranted( + 'CHILL_REPORT_CREATE', + (new Report())->setPerson($person), + 'access denied for report creation' + ); + + $cFGroupId = $request->query->get('cFGroup'); + + if ($cFGroupId) { + return $this->redirect( + $this->generateUrl( + 'report_new', + ['person_id' => $person_id, 'cf_group_id' => $cFGroupId] + ) + ); + } + + $cFGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->findByEntity('Chill\ReportBundle\Entity\Report'); + + if (count($cFGroups) === 1) { + return $this->redirect( + $this->generateUrl( + 'report_new', + ['person_id' => $person_id, 'cf_group_id' => $cFGroups[0]->getId()] + ) + ); + } + + $cFGroupsChoice = []; + + foreach ($cFGroups as $cFGroup) { + $cFGroupsChoice[$cFGroup->getId()] = $cFGroup->getName($request->getLocale()); + } + + $form = $this->get('form.factory') + ->createNamedBuilder(null, FormType::class, null, [ + 'method' => 'GET', + 'csrf_protection' => false, + ]) + ->add('cFGroup', ChoiceType::class, [ + 'choices' => array_combine(array_values($cFGroupsChoice), array_keys($cFGroupsChoice)), + ]) + ->getForm(); + + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + + return $this->render('ChillReportBundle:Report:select_report_type.html.twig', [ + 'form' => $form->createView(), + 'person' => $person, + ]); + } + + /** + * Display a form for selecting which type of report to export + * (a csv file with all the report of this type). + * + * @param Request $request The request + * + * @return Response The web page. + */ + public function selectReportTypeForExportAction(Request $request) + { + $cFGroupId = $request->query->get('cFGroup'); + + if ($cFGroupId) { + return $this->redirect( + $this->generateUrl( + 'report_export_list', + ['cf_group_id' => $cFGroupId] + ) + ); + } + + $em = $this->getDoctrine()->getManager(); + + $cFGroups = $em->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->findByEntity('Chill\ReportBundle\Entity\Report'); + + if (count($cFGroups) === 1) { + return $this->redirect( + $this->generateUrl( + 'report_export_list', + ['cf_group_id' => $cFGroups[0]->getId()] + ) + ); + } + + $cFGroupsChoice = []; + + foreach ($cFGroups as $cFGroup) { + $cFGroupsChoice[$cFGroup->getId()] = $cFGroup->getName($request->getLocale()); + } + + $form = $this->get('form.factory') + ->createNamedBuilder(null, FormType::class, null, [ + 'method' => 'GET', + 'csrf_protection' => false, + ]) + ->add('cFGroup', ChoiceType::class, [ + 'choices' => array_combine(array_values($cFGroupsChoice), array_keys($cFGroupsChoice)), + ]) + ->getForm(); + + return $this->render('ChillReportBundle:Report:select_report_type_for_export.html.twig', [ + 'form' => $form->createView(), + 'layout_name' => '@ChillMain/Export/layout.html.twig', + ]); } /** * Web page for editing an existing report. * - * @param integer $person_id The id of the person. - * @param integer $report_id The id of the report. + * @param int $person_id The id of the person. + * @param int $report_id The id of the report. + * * @return Response The web page. */ public function updateAction($person_id, $report_id, Request $request) @@ -515,7 +447,8 @@ class ReportController extends AbstractController if (!$report) { throw $this->createNotFoundException( - $this->get('translator')->trans('Unable to find this report.')); + $this->get('translator')->trans('Unable to find this report.') + ); } $this->denyAccessUnlessGranted('CHILL_REPORT_UPDATE', $report); @@ -528,34 +461,120 @@ class ReportController extends AbstractController $this->get('session') ->getFlashBag() - ->add('success', + ->add( + 'success', $this->get('translator') ->trans('Success : report updated!') ); - + $person = $report->getPerson(); - - $event = new PrivacyEvent($person, array( + + $event = new PrivacyEvent($person, [ 'element_class' => Report::class, 'element_id' => $report->getId(), - 'action' => 'update' - )); + 'action' => 'update', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->redirect($this->generateUrl('report_view', - array('person_id' => $report->getPerson()->getId(), 'report_id' => $report_id))); + + return $this->redirect($this->generateUrl( + 'report_view', + ['person_id' => $report->getPerson()->getId(), 'report_id' => $report_id] + )); } $this->get('session') ->getFlashBag() - ->add('error', + ->add( + 'error', $this->get('translator') ->trans('The form is not valid. The report has not been updated !') ); - return $this->render('ChillReportBundle:Report:edit.html.twig', array( - 'edit_form' => $editForm->createView(), - 'person' => $report->getPerson() - )); + return $this->render('ChillReportBundle:Report:edit.html.twig', [ + 'edit_form' => $editForm->createView(), + 'person' => $report->getPerson(), + ]); + } + + /** + * Find and display a report. + * + * @param int $report_id The id of the report. + * @param int $person_id The id of the person. + * + * @return Response The web page. + */ + public function viewAction($report_id, $person_id) + { + $em = $this->getDoctrine()->getManager(); + + $person = $em->getRepository('ChillPersonBundle:Person')->find($person_id); + + $entity = $em->getRepository('ChillReportBundle:Report')->find($report_id); + + if (!$entity || !$person) { + throw $this->createNotFoundException( + $this->get('translator')->trans('Unable to find this report.') + ); + } + + $this->denyAccessUnlessGranted('CHILL_REPORT_SEE', $entity); + + $event = new PrivacyEvent($person, [ + 'element_class' => Report::class, + 'element_id' => $entity->getId(), + 'action' => 'view', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillReportBundle:Report:view.html.twig', [ + 'entity' => $entity, + 'person' => $person, + ]); + } + + /** + * Creates a form to create a Report entity. + * + * @param Report $entity The entity + * @param mixed $cFGroup + * + * @return \Symfony\Component\Form\Form The form + */ + private function createCreateForm(Report $entity, Person $person, $cFGroup) + { + return $this->createForm(ReportType::class, $entity, [ + 'action' => $this->generateUrl( + 'report_create', + ['person_id' => $person->getId(), + 'cf_group_id' => $cFGroup->getId(), ] + ), + 'method' => 'POST', + 'cFGroup' => $cFGroup, + 'role' => new Role('CHILL_REPORT_CREATE'), + 'center' => $person->getCenter(), + ]); + } + + /** + * Creates a form to edit a Report entity. + * + * @param Report $entity The report to edit. + * + * @return \Symfony\Component\Form\Form The form + */ + private function createEditForm(Report $entity) + { + return $this->createForm(ReportType::class, $entity, [ + 'action' => $this->generateUrl( + 'report_update', + ['person_id' => $entity->getPerson()->getId(), + 'report_id' => $entity->getId(), ] + ), + 'method' => 'PUT', + 'cFGroup' => $entity->getCFGroup(), + 'role' => new Role('CHILL_REPORT_UPDATE'), + 'center' => $entity->getPerson()->getCenter(), + ]); } } diff --git a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomField.php b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomField.php index 005f7d9ec..6e55c129f 100644 --- a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomField.php +++ b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomField.php @@ -1,33 +1,21 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\DataFixtures\ORM; +use Chill\CustomFieldsBundle\Entity\CustomField; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\CustomFieldsBundle\Entity\CustomField; /** - * Load CustomField for Report into database + * Load CustomField for Report into database. */ class LoadCustomField extends AbstractFixture implements OrderedFixtureInterface { @@ -35,188 +23,176 @@ class LoadCustomField extends AbstractFixture implements OrderedFixtureInterface { return 15001; } - + public function load(ObjectManager $manager) { echo "loading CustomField...\n"; $cFTypes = [ - array('type' => 'text', 'options' => array('maxLength' => '255')), - array('type' => 'text', 'options' => array('maxLength' => '1000')), - array('type' => 'text', 'options' => array('maxLength' => '2000')), - array('type' => 'title', 'options' => array('type' => 'title')), - array('type' => 'title', 'options' => array('type' => 'subtitle')), - array('type' => 'choice', 'options' => array( + ['type' => 'text', 'options' => ['maxLength' => '255']], + ['type' => 'text', 'options' => ['maxLength' => '1000']], + ['type' => 'text', 'options' => ['maxLength' => '2000']], + ['type' => 'title', 'options' => ['type' => 'title']], + ['type' => 'title', 'options' => ['type' => 'subtitle']], + ['type' => 'choice', 'options' => [ 'multiple' => false, - 'expanded'=> false, + 'expanded' => false, 'other' => false, - 'choices'=> [ - array( - 'name' => array( + 'choices' => [ + [ + 'name' => [ 'fr' => 'Options 1 FR', 'nl' => 'Options 1 NL', - 'en' => 'Options 1 EN'), + 'en' => 'Options 1 EN', ], 'active' => true, - 'slug' => 'el-1-fr'), - array( - 'name' => array( + 'slug' => 'el-1-fr', ], + [ + 'name' => [ 'fr' => 'Options 2 FR', 'nl' => 'Options 2 NL', - 'en' => 'Options 2 EN'), + 'en' => 'Options 2 EN', ], 'active' => true, - 'slug' => 'el-2-fr'), - array( - 'name' => array( + 'slug' => 'el-2-fr', ], + [ + 'name' => [ 'fr' => 'Options 2 FR', 'nl' => 'Options 2 NL', - 'en' => 'Options 2 EN'), + 'en' => 'Options 2 EN', ], 'active' => true, - 'slug' => 'el-3-fr') - ] - ) - ) + 'slug' => 'el-3-fr', ], + ], + ], + ], ]; - for($i=0; $i <= 25; $i++) { + for ($i = 0; 25 >= $i; ++$i) { echo "CustomField {$i}\n"; - $cFType = $cFTypes[rand(0,sizeof($cFTypes) - 1)]; + $cFType = $cFTypes[rand(0, sizeof($cFTypes) - 1)]; $customField = (new CustomField()) ->setSlug("cf_report_{$i}") ->setType($cFType['type']) ->setOptions($cFType['options']) - ->setName(array("fr" => "CustomField {$i}")) - ->setOrdering(rand(0,1000) / 1000) - ->setCustomFieldsGroup($this->getReference('cf_group_report_'.(rand(0,3)))) - ; + ->setName(['fr' => "CustomField {$i}"]) + ->setOrdering(rand(0, 1000) / 1000) + ->setCustomFieldsGroup($this->getReference('cf_group_report_' . (rand(0, 3)))); $manager->persist($customField); } - + $this->createExpectedFields($manager); - + $manager->flush(); } - + private function createExpectedFields(ObjectManager $manager) { //report logement $reportLogement = $this->getReference('cf_group_report_logement'); - + $houseTitle = (new CustomField()) - ->setSlug('house_title') - ->setType('title') - ->setOptions(array('type' => 'title')) - ->setName(array('fr' => 'Situation de logement')) - ->setOrdering(10) - ->setCustomFieldsGroup($reportLogement) - ; + ->setSlug('house_title') + ->setType('title') + ->setOptions(['type' => 'title']) + ->setName(['fr' => 'Situation de logement']) + ->setOrdering(10) + ->setCustomFieldsGroup($reportLogement); $manager->persist($houseTitle); - + $hasLogement = (new CustomField()) - ->setSlug('has_logement') - ->setName(array('fr' => 'Logement actuel')) - ->setType('choice') - ->setOptions(array( - 'multiple' => FALSE, - 'expanded' => TRUE, - 'other' => TRUE, - 'choices' => [ - array( - 'name' => ['fr' => 'Locataire d\' un logement'], - 'slug' => 'rent_house', - 'active' => true - ), - array( - 'name' => ['fr' => 'Propriétaire d\' un logement'], - 'slug' => 'own_house', - 'active' => true - ), - array( - 'name' => ['fr' => 'Par-ci, par là (amis, famille, ...)'], - 'slug' => 'here-and-there', - 'active' => true - ), - array( - 'name' => ['fr' => 'A la rue'], - 'slug' => 'street', - 'active' => true - ) - ] - - )) - ->setOrdering(20) - ->setCustomFieldsGroup($reportLogement) - ; + ->setSlug('has_logement') + ->setName(['fr' => 'Logement actuel']) + ->setType('choice') + ->setOptions([ + 'multiple' => false, + 'expanded' => true, + 'other' => true, + 'choices' => [ + [ + 'name' => ['fr' => 'Locataire d\' un logement'], + 'slug' => 'rent_house', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Propriétaire d\' un logement'], + 'slug' => 'own_house', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Par-ci, par là (amis, famille, ...)'], + 'slug' => 'here-and-there', + 'active' => true, + ], + [ + 'name' => ['fr' => 'A la rue'], + 'slug' => 'street', + 'active' => true, + ], + ], + ]) + ->setOrdering(20) + ->setCustomFieldsGroup($reportLogement); $manager->persist($hasLogement); - + $descriptionLogement = (new CustomField()) - ->setSlug('house-desc') - ->setName(array('fr' => 'Plaintes éventuelles sur le logement')) - ->setType('text') - ->setOptions(['maxLength' => 1500]) - ->setOrdering(30) - ->setCustomFieldsGroup($reportLogement) - ; + ->setSlug('house-desc') + ->setName(['fr' => 'Plaintes éventuelles sur le logement']) + ->setType('text') + ->setOptions(['maxLength' => 1500]) + ->setOrdering(30) + ->setCustomFieldsGroup($reportLogement); $manager->persist($descriptionLogement); - - + //report problems $reportEducation = $this->getReference('cf_group_report_education'); - + $title = (new CustomField()) - ->setSlug('title') - ->setType('title') - ->setOptions(array('type' => 'title')) - ->setName(array('fr' => 'Éducation')) - ->setOrdering(10) - ->setCustomFieldsGroup($reportEducation) - ; + ->setSlug('title') + ->setType('title') + ->setOptions(['type' => 'title']) + ->setName(['fr' => 'Éducation']) + ->setOrdering(10) + ->setCustomFieldsGroup($reportEducation); $manager->persist($title); - + $educationLevel = (new CustomField()) - ->setSlug('level') - ->setName(array('fr' => 'Niveau du plus haut diplôme')) - ->setType('choice') - ->setOptions(array( - 'multiple' => FALSE, - 'expanded' => FALSE, - 'other' => FALSE, - 'choices' => [ - array( - 'name' => ['fr' => 'Supérieur'], - 'slug' => 'superieur', - 'active' => true - ), - array( - 'name' => ['fr' => 'Secondaire supérieur (CESS)'], - 'slug' => 'cess', - 'active' => true - ), - array( - 'name' => ['fr' => 'Secondaire deuxième degré ou inférieur (C2D)'], - 'slug' => 'c2d', - 'active' => true - ), - array( - 'name' => ['fr' => 'Primaire'], - 'slug' => 'low', - 'active' => true - ), - array( - 'name' => ['fr' => 'Aucun diplome'], - 'slug' => 'no', - 'active' => true - ) - ] - - )) - ->setOrdering(20) - ->setCustomFieldsGroup($reportEducation) - ; + ->setSlug('level') + ->setName(['fr' => 'Niveau du plus haut diplôme']) + ->setType('choice') + ->setOptions([ + 'multiple' => false, + 'expanded' => false, + 'other' => false, + 'choices' => [ + [ + 'name' => ['fr' => 'Supérieur'], + 'slug' => 'superieur', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Secondaire supérieur (CESS)'], + 'slug' => 'cess', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Secondaire deuxième degré ou inférieur (C2D)'], + 'slug' => 'c2d', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Primaire'], + 'slug' => 'low', + 'active' => true, + ], + [ + 'name' => ['fr' => 'Aucun diplome'], + 'slug' => 'no', + 'active' => true, + ], + ], + ]) + ->setOrdering(20) + ->setCustomFieldsGroup($reportEducation); $manager->persist($educationLevel); - - - } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomFieldsGroup.php b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomFieldsGroup.php index ee45cc728..1d59a9732 100644 --- a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomFieldsGroup.php +++ b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadCustomFieldsGroup.php @@ -1,33 +1,21 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\DataFixtures\ORM; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; /** - * Load CustomFieldsGroup for Report into database + * Load CustomFieldsGroup for Report into database. */ class LoadCustomFieldsGroup extends AbstractFixture implements OrderedFixtureInterface { @@ -35,55 +23,52 @@ class LoadCustomFieldsGroup extends AbstractFixture implements OrderedFixtureInt { return 15000; } - + public function load(ObjectManager $manager) { echo "loading customFieldsGroup...\n"; - - $report = $this->createReport($manager, - array('fr' => 'Situation de logement'), - ['summary_fields' => ['has_logement', 'house-desc']]); + + $report = $this->createReport( + $manager, + ['fr' => 'Situation de logement'], + ['summary_fields' => ['has_logement', 'house-desc']] + ); $this->addReference( - 'cf_group_report_logement', - $report - ); - - $report = $this->createReport($manager, array('fr' => 'Alphabétisme')); + 'cf_group_report_logement', + $report + ); + + $report = $this->createReport($manager, ['fr' => 'Alphabétisme']); $this->addReference('cf_group_report_education', $report); - for($i=0; $i <= 3; $i++) { - - $report = $this->createReport($manager, array('fr' => 'ZZ Rapport aléatoire '.$i)); + for ($i = 0; 3 >= $i; ++$i) { + $report = $this->createReport($manager, ['fr' => 'ZZ Rapport aléatoire ' . $i]); - $this->addReference('cf_group_report_'.$i, $report); + $this->addReference('cf_group_report_' . $i, $report); } - - - + $manager->flush(); } - + /** - * create a report and persist in the db - * - * @param ObjectManager $manager - * @param array $name + * create a report and persist in the db. + * * @return CustomFieldsGroup */ private function createReport( - ObjectManager $manager, - array $name, - array $options = array()) - { - echo $name['fr']." \n"; - + ObjectManager $manager, + array $name, + array $options = [] + ) { + echo $name['fr'] . " \n"; + $cFGroup = (new CustomFieldsGroup()) ->setName($name) ->setEntity('Chill\ReportBundle\Entity\Report') ->setOptions($options); $manager->persist($cFGroup); - + return $cFGroup; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReportACL.php b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReportACL.php index f2a97c16d..181d007bc 100644 --- a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReportACL.php +++ b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReportACL.php @@ -1,36 +1,24 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\Entity\RoleScope; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; /** * Add a role CHILL_REPORT_UPDATE & CHILL_REPORT_CREATE for all groups except administrative, - * and a role CHILL_REPORT_SEE for administrative - * - * @author Julien Fastré + * and a role CHILL_REPORT_SEE for administrative. */ class LoadReportACL extends AbstractFixture implements OrderedFixtureInterface { @@ -39,13 +27,13 @@ class LoadReportACL extends AbstractFixture implements OrderedFixtureInterface return 14999; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); printf("processing permission group %s \n", $permissionsGroup->getName()); - foreach (LoadScopes::$references as $scopeRef){ + + foreach (LoadScopes::$references as $scopeRef) { $scope = $this->getReference($scopeRef); printf("processing scope %s \n", $scope->getName()['en']); //create permission group @@ -53,36 +41,42 @@ class LoadReportACL extends AbstractFixture implements OrderedFixtureInterface case 'social': if ($scope->getName()['en'] === 'administrative') { printf("denying power on administrative \n"); + break 2; // we do not want any power on administrative } + break; + case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], ['administrative', 'social'])) { printf("denying power on %s\n", $scope->getName()['en']); + break 2; // we do not want any power on social or administrative - } + } + break; } - - printf("Adding CHILL_REPORT_UPDATE & CHILL_REPORT_CREATE to %s " - . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); + + printf( + 'Adding CHILL_REPORT_UPDATE & CHILL_REPORT_CREATE to %s ' + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), + $scope->getName()['en'] + ); $roleScopeUpdate = (new RoleScope()) - ->setRole('CHILL_REPORT_UPDATE') - ->setScope($scope); + ->setRole('CHILL_REPORT_UPDATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreate = (new RoleScope()) - ->setRole('CHILL_REPORT_CREATE') - ->setScope($scope); + ->setRole('CHILL_REPORT_CREATE') + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $manager->persist($roleScopeUpdate); $manager->persist($roleScopeCreate); } - } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php index 180491c1f..84ca87b40 100644 --- a/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php +++ b/src/Bundle/ChillReportBundle/DataFixtures/ORM/LoadReports.php @@ -1,240 +1,225 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\DataFixtures\ORM; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\DataFixtures\ORM\LoadUsers; +use Chill\ReportBundle\Entity\Report; +use DateTime; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; -use Chill\ReportBundle\Entity\Report; -use Chill\MainBundle\DataFixtures\ORM\LoadUsers; use Faker\Factory as FakerFactory; -use Chill\CustomFieldsBundle\Entity\CustomField; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; /** - * Load reports into DB - * - * @author Julien Fastré + * Load reports into DB. */ class LoadReports extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - + /** - * - * @var \Faker\Generator + * @var \Faker\Generator */ private $faker; - + public function __construct() { $this->faker = FakerFactory::create('fr_FR'); } - + public function getOrder() { return 15002; } - + public function load(ObjectManager $manager) { $this->createExpected($manager); - + //create random 2 times, to allow multiple report on some people $this->createRandom($manager, 90); $this->createRandom($manager, 30); - + $manager->flush(); } - + + private function createExpected(ObjectManager $manager) + { + $charline = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillPersonBundle:Person') + ->findOneBy(['firstName' => 'Charline', 'lastName' => 'Depardieu']); + + $report = (new Report()) + ->setPerson($charline) + ->setCFGroup($this->getReference('cf_group_report_logement')) + ->setDate(new DateTime('2015-01-05')) + ->setScope($this->getReference('scope_social')); + $this->fillReport($report); + + $manager->persist($report); + } + private function createRandom(ObjectManager $manager, $percentage) { $people = $this->getPeopleRandom($percentage); - + foreach ($people as $person) { //create a report, set logement or education report $report = (new Report()) - ->setPerson($person) - ->setCFGroup(rand(0,10) > 5 ? + ->setPerson($person) + ->setCFGroup( + rand(0, 10) > 5 ? $this->getReference('cf_group_report_logement') : $this->getReference('cf_group_report_education') - ) - ->setScope($this->getScopeRandom()) - ; + ) + ->setScope($this->getScopeRandom()); $this->fillReport($report); $manager->persist($report); } } - - private function createExpected(ObjectManager $manager) - { - $charline = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillPersonBundle:Person') - ->findOneBy(array('firstName' => 'Charline', 'lastName' => 'Depardieu')) - ; - - $report = (new Report()) - ->setPerson($charline) - ->setCFGroup($this->getReference('cf_group_report_logement')) - ->setDate(new \DateTime('2015-01-05')) - ->setScope($this->getReference('scope_social')) - ; - $this->fillReport($report); - - $manager->persist($report); - } - - /** - * - * @return \Chill\MainBundle\Entity\Scope - */ - private function getScopeRandom() - { - $ref = LoadScopes::$references[array_rand(LoadScopes::$references)]; - return $this->getReference($ref); - } - - private function getPeopleRandom($percentage) - { - $people = $this->container->get('doctrine.orm.entity_manager') - ->getRepository('ChillPersonBundle:Person') - ->findAll() - ; - - //keep only a part ($percentage) of the people - $selectedPeople = array(); - foreach($people as $person) { - if (rand(0,100) < $percentage) { - $selectedPeople[] = $person; - } - } - - return $selectedPeople; - } - + private function fillReport(Report $report) { //setUser $usernameRef = array_rand(LoadUsers::$refs); $report->setUser( - $this->getReference($usernameRef) - ); - + $this->getReference($usernameRef) + ); + //set date if null - if ($report->getDate() === NULL) { + if ($report->getDate() === null) { //set date. 30% of the dates are 2015-05-01 - $expectedDate = new \DateTime('2015-01-05'); - if (rand(0,100) < 30) { + $expectedDate = new DateTime('2015-01-05'); + + if (rand(0, 100) < 30) { $report->setDate($expectedDate); } else { $report->setDate($this->faker->dateTimeBetween('-1 year', 'now') - ->setTime(0, 0, 0)); - } + ->setTime(0, 0, 0)); + } } - + //fill data - $datas = array(); + $datas = []; + foreach ($report->getCFGroup()->getCustomFields() as $field) { switch ($field->getType()) { - case 'title' : - $datas[$field->getSlug()] = array(); + case 'title': + $datas[$field->getSlug()] = []; + break; - case 'choice' : + + case 'choice': $datas[$field->getSlug()] = $this->getRandomChoice($field); + break; - case 'text' : + + case 'text': $datas[$field->getSlug()] = $this->faker->realText($field->getOptions()['maxLength']); + break; } } $report->setCFData($datas); - + return $report; } - + + private function getPeopleRandom($percentage) + { + $people = $this->container->get('doctrine.orm.entity_manager') + ->getRepository('ChillPersonBundle:Person') + ->findAll(); + + //keep only a part ($percentage) of the people + $selectedPeople = []; + + foreach ($people as $person) { + if (rand(0, 100) < $percentage) { + $selectedPeople[] = $person; + } + } + + return $selectedPeople; + } + /** - * pick a random choice - * - * @param CustomField $field - * @return string[]|string the array of slug if multiple, a single slug otherwise + * pick a random choice. + * + * @return string|string[] the array of slug if multiple, a single slug otherwise */ - private function getRandomChoice(CustomField $field) + private function getRandomChoice(CustomField $field) { $choices = $field->getOptions()['choices']; $multiple = $field->getOptions()['multiple']; $other = $field->getOptions()['other']; - + //add other if allowed - if($other) { - $choices[] = array('slug' => '_other'); + if ($other) { + $choices[] = ['slug' => '_other']; } - + //initialize results - $picked = array(); - + $picked = []; + if ($multiple) { - $numberSelected = rand(1, count($choices) -1); - for ($i = 0; $i < $numberSelected; $i++) { + $numberSelected = rand(1, count($choices) - 1); + + for ($i = 0; $i < $numberSelected; ++$i) { $picked[] = $this->pickChoice($choices); } - + if ($other) { - $result = array("_other" => NULL, "_choices" => $picked); - + $result = ['_other' => null, '_choices' => $picked]; + if (in_array('_other', $picked)) { $result['_other'] = $this->faker->realText(70); } - + return $result; } - } else { $picked = $this->pickChoice($choices); - + if ($other) { - $result = array('_other' => NULL, '_choices' => $picked); - - if ($picked === '_other') { + $result = ['_other' => null, '_choices' => $picked]; + + if ('_other' === $picked) { $result['_other'] = $this->faker->realText(70); } - + return $result; } } - - } - + /** - * pick a choice within a 'choices' options (for choice type) - * - * @param array $choices + * @return \Chill\MainBundle\Entity\Scope + */ + private function getScopeRandom() + { + $ref = LoadScopes::$references[array_rand(LoadScopes::$references)]; + + return $this->getReference($ref); + } + + /** + * pick a choice within a 'choices' options (for choice type). + * * @return the slug of the selected choice */ private function pickChoice(array $choices) { return $choices[array_rand($choices)]['slug']; } - - - } diff --git a/src/Bundle/ChillReportBundle/DependencyInjection/ChillReportExtension.php b/src/Bundle/ChillReportBundle/DependencyInjection/ChillReportExtension.php index 359017020..8e0294d43 100644 --- a/src/Bundle/ChillReportBundle/DependencyInjection/ChillReportExtension.php +++ b/src/Bundle/ChillReportBundle/DependencyInjection/ChillReportExtension.php @@ -1,101 +1,72 @@ getParameter('kernel.bundles'); + + if (!isset($bundles['ChillCustomFieldsBundle'])) { + throw new MissingBundleException('ChillCustomFieldsBundle'); + } + + $container->prependExtensionConfig( + 'chill_custom_fields', + ['customizables_entities' => [ + [ + 'class' => 'Chill\ReportBundle\Entity\Report', + 'name' => 'ReportEntity', + 'options' => [ + 'summary_fields' => [ + 'form_type' => LinkedCustomFieldsType::class, + 'form_options' => [ + 'multiple' => true, + 'expanded' => false, + ], + ], + ], ], + ], + ] + ); + } + public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/fixtures.yaml'); $loader->load('services/export.yaml'); $loader->load('services/controller.yaml'); } - /** - * Declare the entity Report, as a customizable entity (can add custom fields) - * - * @param ContainerBuilder $container - */ - public function declareReportAsCustomizable(ContainerBuilder $container) - { - $bundles = $container->getParameter('kernel.bundles'); - if (!isset($bundles['ChillCustomFieldsBundle'])) { - throw new MissingBundleException('ChillCustomFieldsBundle'); - } - - $container->prependExtensionConfig('chill_custom_fields', - array('customizables_entities' => - array( - array( - 'class' => 'Chill\ReportBundle\Entity\Report', - 'name' => 'ReportEntity', - 'options' => array( - 'summary_fields' => array( - 'form_type' => LinkedCustomFieldsType::class, - 'form_options' => - [ - 'multiple' => true, - 'expanded' => false - ] - ) - )) - ) - ) - ); - } - - /** - * declare routes from report bundle - * - * @param ContainerBuilder $container - */ - private function declareRouting(ContainerBuilder $container) - { - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillReportBundle/config/routes.yaml' - ) - ) - )); - } - - protected function prependRoleHierarchy(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - 'CHILL_REPORT_UPDATE' => array('CHILL_REPORT_SEE'), - 'CHILL_REPORT_CREATE' => array('CHILL_REPORT_SEE') - ) - )); - } - - /** - * {@inheritdoc} - * - * @param ContainerBuilder $container - */ public function prepend(ContainerBuilder $container) { $this->declareReportAsCustomizable($container); @@ -103,4 +74,27 @@ class ChillReportExtension extends Extension implements PrependExtensionInterfac $this->prependRoleHierarchy($container); } + protected function prependRoleHierarchy(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + 'CHILL_REPORT_UPDATE' => ['CHILL_REPORT_SEE'], + 'CHILL_REPORT_CREATE' => ['CHILL_REPORT_SEE'], + ], + ]); + } + + /** + * declare routes from report bundle. + */ + private function declareRouting(ContainerBuilder $container) + { + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillReportBundle/config/routes.yaml', + ], + ], + ]); + } } diff --git a/src/Bundle/ChillReportBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillReportBundle/DependencyInjection/Configuration.php index 2b3b75672..81c652be1 100644 --- a/src/Bundle/ChillReportBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillReportBundle/DependencyInjection/Configuration.php @@ -1,20 +1,24 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Chill\MainBundle\Entity\User; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\MainBundle\Entity\Center; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; -use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; +use Chill\PersonBundle\Entity\Person; +use DateTime; +use Doctrine\ORM\Mapping as ORM; /** - * Class Report + * Class Report. * - * @package Chill\ReportBundle\Entity - * @ORM\Entity() + * @ORM\Entity * @ORM\Table(name="report") - * @ORM\HasLifecycleCallbacks() + * @ORM\HasLifecycleCallbacks */ class Report implements HasCenterInterface, HasScopeInterface { - /** - * @var integer - * - * @ORM\Id - * @ORM\Column(name="id", type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - private $id; - - /** - * @var User - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") - */ - private $user; - - /** - * @var Person - * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") - */ - private $person; - - /** - * @var \DateTime - * @ORM\Column(type="datetime") - */ - private $date; - - /** - * @var Scope - * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") - */ - private $scope; - /** * @var array * @ORM\Column(type="json_array") @@ -81,15 +37,85 @@ class Report implements HasCenterInterface, HasScopeInterface /** * @var CustomFieldsGroup * @ORM\ManyToOne( - * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup") + * targetEntity="Chill\CustomFieldsBundle\Entity\CustomFieldsGroup") */ private $cFGroup; + /** + * @var DateTime + * @ORM\Column(type="datetime") + */ + private $date; /** - * Get id + * @var int * - * @return integer + * @ORM\Id + * @ORM\Column(name="id", type="integer") + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var Person + * @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\Person") + */ + private $person; + + /** + * @var Scope + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Scope") + */ + private $scope; + + /** + * @var User + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User") + */ + private $user; + + /** + * @return Center + */ + public function getCenter() + { + return $this->person->getCenter(); + } + + /** + * Get cFData. + * + * @return array + */ + public function getCFData() + { + return $this->cFData; + } + + /** + * Get cFGroup. + * + * @return CustomFieldsGroup + */ + public function getCFGroup() + { + return $this->cFGroup; + } + + /** + * Get date. + * + * @return DateTime + */ + public function getDate() + { + return $this->date; + } + + /** + * Get id. + * + * @return int */ public function getId() { @@ -97,43 +123,7 @@ class Report implements HasCenterInterface, HasScopeInterface } /** - * Set user - * - * @param User $user - * @return Report - */ - public function setUser(User $user) - { - $this->user = $user; - - return $this; - } - - /** - * Get user - * - * @return User - */ - public function getUser() - { - return $this->user; - } - - /** - * Set person - * - * @param Person $person - * @return Report - */ - public function setPerson(Person $person) - { - $this->person = $person; - - return $this; - } - - /** - * Get person + * Get person. * * @return Person */ @@ -143,43 +133,7 @@ class Report implements HasCenterInterface, HasScopeInterface } /** - * Set date - * - * @param \DateTime $date - * @return Report - */ - public function setDate($date) - { - $this->date = $date; - - return $this; - } - - /** - * Get date - * - * @return \DateTime - */ - public function getDate() - { - return $this->date; - } - - /** - * Set scope - * - * @param string $scope - * @return Report - */ - public function setScope(Scope $scope) - { - $this->scope = $scope; - - return $this; - } - - /** - * Get scope + * Get scope. * * @return Scope */ @@ -189,9 +143,18 @@ class Report implements HasCenterInterface, HasScopeInterface } /** - * Set cFData + * Get user. + * + * @return User + */ + public function getUser() + { + return $this->user; + } + + /** + * Set cFData. * - * @param array $cFData * @return Report */ public function setCFData(array $cFData) @@ -202,19 +165,8 @@ class Report implements HasCenterInterface, HasScopeInterface } /** - * Get cFData + * Set cFGroup. * - * @return array - */ - public function getCFData() - { - return $this->cFData; - } - - /** - * Set cFGroup - * - * @param CustomFieldsGroup $cFGroup * @return Report */ public function setCFGroup(CustomFieldsGroup $cFGroup) @@ -225,21 +177,54 @@ class Report implements HasCenterInterface, HasScopeInterface } /** - * Get cFGroup + * Set date. * - * @return CustomFieldsGroup + * @param DateTime $date + * + * @return Report */ - public function getCFGroup() + public function setDate($date) { - return $this->cFGroup; - } - - /** - * @return Center - */ - public function getCenter() - { - return $this->person->getCenter(); + $this->date = $date; + + return $this; } + /** + * Set person. + * + * @return Report + */ + public function setPerson(Person $person) + { + $this->person = $person; + + return $this; + } + + /** + * Set scope. + * + * @param string $scope + * + * @return Report + */ + public function setScope(Scope $scope) + { + $this->scope = $scope; + + return $this; + } + + /** + * Set user. + * + * @return Report + */ + public function setUser(User $user) + { + $this->user = $user; + + return $this; + } } diff --git a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php index 583db8f4b..d2d56cf15 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportList.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportList.php @@ -1,77 +1,84 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\ReportBundle\Export\Export; + +use Chill\CustomFieldsBundle\CustomFields\CustomFieldChoice; +use Chill\CustomFieldsBundle\Entity\CustomField; +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Export\ExportElementValidatedInterface; +use Chill\MainBundle\Export\FormatterInterface; +use Chill\MainBundle\Export\ListInterface; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\PersonBundle\Export\Declarations; +use Chill\ReportBundle\Entity\Report; +use Chill\ReportBundle\Security\Authorization\ReportVoter; +use DateTime; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Query; +use Exception; +use LogicException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Context\ExecutionContextInterface; + +use function array_key_exists; +use function array_keys; +use function array_merge; +use function strlen; +use function strtolower; +use function ucfirst; +use function uniqid; + class ReportList implements ListInterface, ExportElementValidatedInterface { /** - * - * @var CustomFieldsGroup - */ - protected $customfieldsGroup; - - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var CustomFieldProvider */ protected $customFieldProvider; - + + /** + * @var CustomFieldsGroup + */ + protected $customfieldsGroup; + protected $em; - - protected $fields = array( + + protected $fields = [ 'person_id', 'person_firstName', 'person_lastName', 'person_birthdate', 'person_placeOfBirth', 'person_gender', 'person_memo', 'person_email', 'person_phonenumber', 'person_countryOfBirth', 'person_nationality', 'person_address_street_address_1', 'person_address_street_address_2', 'person_address_valid_from', 'person_address_postcode_label', 'person_address_postcode_code', 'person_address_country_name', 'person_address_country_code', - 'report_id', 'report_user', 'report_date', 'report_scope' - ); - + 'report_id', 'report_user', 'report_date', 'report_scope', + ]; + protected $slugs = []; - - function __construct( - CustomFieldsGroup $customfieldsGroup, + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** + * @var TranslatorInterface + */ + protected $translator; + + public function __construct( + CustomFieldsGroup $customfieldsGroup, TranslatableStringHelper $translatableStringHelper, TranslatorInterface $translator, CustomFieldProvider $customFieldProvider, @@ -84,118 +91,84 @@ class ReportList implements ListInterface, ExportElementValidatedInterface $this->em = $em; } - public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $choices = array_combine($this->fields, $this->fields); - + $choices = array_combine($this->fields, $this->fields); + foreach ($this->getCustomFields() as $cf) { - $choices - [$this->translatableStringHelper->localize($cf->getName())] - = + $choices[$this->translatableStringHelper->localize($cf->getName())] + = $cf->getSlug(); } - + // Add a checkbox to select fields - $builder->add('fields', ChoiceType::class, array( + $builder->add('fields', ChoiceType::class, [ 'multiple' => true, 'expanded' => true, 'choices' => $choices, - 'label' => 'Fields to include in export', - 'choice_attr' => function($val, $key, $index) { + 'label' => 'Fields to include in export', + 'choice_attr' => function ($val, $key, $index) { // add a 'data-display-target' for address fields if (substr($val, 0, 8) === 'address_') { return ['data-display-target' => 'address_date']; - } else { - return []; } + + return []; }, - 'choice_label' => function($key, $label) { + 'choice_label' => function ($key, $label) { switch (\substr($key, 0, 7)) { case 'person_': - return $this->translator->trans(\substr($key, 7, \strlen($key) - 7)). - ' ('.$this->translator->trans('Person').')'; + return $this->translator->trans(\substr($key, 7, strlen($key) - 7)) . + ' (' . $this->translator->trans('Person') . ')'; + case 'report_': - return $this->translator->trans(\ucfirst(\substr($key, 7, \strlen($key) - 7))). - ' ('.$this->translator->trans('Report').')'; + return $this->translator->trans(ucfirst(\substr($key, 7, strlen($key) - 7))) . + ' (' . $this->translator->trans('Report') . ')'; + default: - return $label. - ' ('.$this->translator->trans("Report's question").')';; + return $label . + ' (' . $this->translator->trans("Report's question") . ')'; } }, - 'constraints' => [new Callback(array( - 'callback' => function($selected, ExecutionContextInterface $context) { + 'constraints' => [new Callback([ + 'callback' => function ($selected, ExecutionContextInterface $context) { if (count($selected) === 0) { $context->buildViolation('You must select at least one element') ->atPath('fields') ->addViolation(); } - } - ))] - )); - + }, + ])], + ]); + // add a date field for addresses - $builder->add('address_date', ChillDateType::class, array( - 'label' => "Address valid at this date", - 'data' => new \DateTime(), + $builder->add('address_date', ChillDateType::class, [ + 'label' => 'Address valid at this date', + 'data' => new DateTime(), 'required' => false, - 'block_name' => 'list_export_form_address_date' - )); - } - - public function validateForm($data, ExecutionContextInterface $context) - { - // get the field starting with address_ - $addressFields = array_filter(function($el) { - return substr($el, 0, 8) === 'address_'; - }, $this->fields); - - // check if there is one field starting with address in data - if (count(array_intersect($data['fields'], $addressFields)) > 0) { - // if a field address is checked, the date must not be empty - if (empty($data['address_date'])) { - $context - ->buildViolation("You must set this date if an address is checked") - ->atPath('address_date') - ->addViolation(); - } - } - } - - /** - * Get custom fields associated with person - * - * @return CustomField[] - */ - private function getCustomFields() - { - return \array_filter($this->customfieldsGroup - ->getCustomFields()->toArray(), function(CustomField $cf) { - return $cf->getType() !== 'title'; - }); + 'block_name' => 'list_export_form_address_date', + ]); } public function getAllowedFormattersTypes() { - return array(FormatterInterface::TYPE_LIST); + return [FormatterInterface::TYPE_LIST]; } public function getDescription() { return $this->translator->trans( "Generate list of report '%type%'", - [ - '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()) + [ + '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()), ] ); } /** - * {@inheritDoc} - * * @param type $key - * @param array $values * @param type $data + * * @return type */ public function getLabels($key, array $values, $data) @@ -205,214 +178,145 @@ class ReportList implements ListInterface, ExportElementValidatedInterface case 'report_date': // for birthdate or report date, we have to transform the string into a date // to format the date correctly. - return function($value) use ($key) { - if ($value === '_header') { - return $key === 'person_birthdate' ? 'birthdate' : 'report_date'; + return function ($value) use ($key) { + if ('_header' === $value) { + return 'person_birthdate' === $key ? 'birthdate' : 'report_date'; } - - if (empty($value)) - { - return ""; + + if (empty($value)) { + return ''; } - - if ($key === 'person_birthdate') { - $date = \DateTime::createFromFormat('Y-m-d', $value); + + if ('person_birthdate' === $key) { + $date = DateTime::createFromFormat('Y-m-d', $value); } else { - $date = \DateTime::createFromFormat('Y-m-d H:i:s', $value); + $date = DateTime::createFromFormat('Y-m-d H:i:s', $value); } // check that the creation could occurs. - if ($date === false) { - throw new \Exception(sprintf("The value %s could " - . "not be converted to %s", $value, \DateTime::class)); + if (false === $date) { + throw new Exception(sprintf('The value %s could ' + . 'not be converted to %s', $value, DateTime::class)); } - - return $date->format('d-m-Y'); + + return $date->format('d-m-Y'); }; + case 'report_scope': $qb = $this->em->getRepository(Scope::class) ->createQueryBuilder('s'); $qb->addSelect('s.name') ->addSelect('s.id') - ->where($qb->expr()->in('s.id', $values)) - ; + ->where($qb->expr()->in('s.id', $values)); $rows = $qb->getQuery()->getResult(Query::HYDRATE_ARRAY); - - foreach($rows as $row) { + + foreach ($rows as $row) { $scopes[$row['id']] = $this->translatableStringHelper ->localize($row['name']); } - - return function($value) use ($scopes) { - if ($value === '_header') { + + return function ($value) use ($scopes) { + if ('_header' === $value) { return 'circle'; } - + return $scopes[$value]; }; + case 'report_user': $qb = $this->em->getRepository(User::class) ->createQueryBuilder('u'); $qb->addSelect('u.username') ->addSelect('u.id') - ->where($qb->expr()->in('u.id', $values)) - ; + ->where($qb->expr()->in('u.id', $values)); $rows = $qb->getQuery()->getResult(Query::HYDRATE_ARRAY); - - foreach($rows as $row) { + + foreach ($rows as $row) { $users[$row['id']] = $row['username']; } - - return function($value) use ($users) { - if ($value === '_header') { + + return function ($value) use ($users) { + if ('_header' === $value) { return 'user'; } - + return $users[$value]; }; - case 'person_gender' : + + case 'person_gender': // for gender, we have to translate men/women statement - return function($value) { - if ($value === '_header') { return 'gender'; } - + return function ($value) { + if ('_header' === $value) { + return 'gender'; + } + return $this->translator->trans($value); }; + case 'person_countryOfBirth': case 'person_nationality': $countryRepository = $this->em ->getRepository('ChillMainBundle:Country'); - + // load all countries in a single query - $countryRepository->findBy(array('countryCode' => $values)); - - return function($value) use ($key, $countryRepository) { - if ($value === '_header') { return \strtolower($key); } - - if ($value === NULL) { + $countryRepository->findBy(['countryCode' => $values]); + + return function ($value) use ($key, $countryRepository) { + if ('_header' === $value) { + return strtolower($key); + } + + if (null === $value) { return $this->translator->trans('no data'); } - + $country = $countryRepository->find($value); - + return $this->translatableStringHelper->localize( - $country->getName()); + $country->getName() + ); }; + case 'person_address_country_name': - return function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } - - if ($value === NULL) { + return function ($value) use ($key) { + if ('_header' === $value) { + return strtolower($key); + } + + if (null === $value) { return ''; } - + return $this->translatableStringHelper->localize(json_decode($value, true)); }; + default: // for fields which are associated with person if (in_array($key, $this->fields)) { - return function($value) use ($key) { - if ($value === '_header') { return \strtolower($key); } + return function ($value) use ($key) { + if ('_header' === $value) { + return strtolower($key); + } - return $value; - - }; + return $value; + }; } else { return $this->getLabelForCustomField($key, $values, $data); } } - - } - - private function getLabelForCustomField($key, array $values, $data) - { - // for fields which are custom fields - /* @var $cf CustomField */ - $cf = $this->em - ->getRepository(CustomField::class) - ->findOneBy(array('slug' => $this->DQLToSlug($key))); - - $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); - $defaultFunction = function($value) use ($cf) { - if ($value === '_header') { - return $this->translatableStringHelper->localize($cf->getName()); - } - - return $this->customFieldProvider - ->getCustomFieldByType($cf->getType()) - ->render(json_decode($value, true), $cf, 'csv'); - }; - - if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { - return function($value) use ($cf, $cfType, $key) { - $slugChoice = $this->extractInfosFromSlug($key)['additionnalInfos']['choiceSlug']; - $decoded = \json_decode($value, true); - - if ($value === '_header') { - - $label = $cfType->getChoices($cf)[$slugChoice]; - - return $this->translatableStringHelper->localize($cf->getName()) - .' | '.$label; - } - - if ($slugChoice === '_other' and $cfType->isChecked($cf, $choiceSlug, $decoded)) { - return $cfType->extractOtherValue($cf, $decoded); - } else { - return $cfType->isChecked($cf, $slugChoice, $decoded); - } - }; - - } else { - return $defaultFunction; - } } public function getQueryKeys($data) { - $fields = array(); - + $fields = []; + foreach ($data['fields'] as $key) { if (in_array($key, $this->fields)) { $fields[] = $key; } } - + // add the key from slugs and return - return \array_merge($fields, \array_keys($this->slugs)); - } - - /** - * clean a slug to be usable by DQL - * - * @param string $slugsanitize - * @param string $type the type of the customfield, if required (currently only for choices) - * @return string - */ - private function slugToDQL($slug, $type = "default", array $additionalInfos = []) - { - $uid = 'slug_'.\uniqid(); - - $this->slugs[$uid] = [ - 'slug' => $slug, - 'type' => $type, - 'additionnalInfos' => $additionalInfos - ]; - - return $uid; - } - - private function DQLToSlug($cleanedSlug) - { - return $this->slugs[$cleanedSlug]['slug']; - } - - /** - * - * @param type $cleanedSlug - * @return an array with keys = 'slug', 'type', 'additionnalInfo' - */ - private function extractInfosFromSlug($slug) - { - return $this->slugs[$slug]; + return array_merge($fields, array_keys($this->slugs)); } public function getResult($query, $data) @@ -424,8 +328,8 @@ class ReportList implements ListInterface, ExportElementValidatedInterface { return $this->translator->trans( "List for report '%type%'", - [ - '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()) + [ + '%type%' => $this->translatableStringHelper->localize($this->customfieldsGroup->getName()), ] ); } @@ -435,32 +339,36 @@ class ReportList implements ListInterface, ExportElementValidatedInterface return 'report'; } - 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 - if (!\array_key_exists('fields', $data)) { - throw new \Doctrine\DBAL\Exception\InvalidArgumentException("any fields " - . "have been checked"); + if (!array_key_exists('fields', $data)) { + throw new \Doctrine\DBAL\Exception\InvalidArgumentException('any fields ' + . 'have been checked'); } - + $qb = $this->em->createQueryBuilder(); - + // process fields which are not custom fields foreach ($this->fields as $f) { // do not add fields which are not selected if (!\in_array($f, $data['fields'])) { continue; } - + // add a column to the query for each field switch ($f) { case 'person_countryOfBirth': case 'person_nationality': $suffix = \substr($f, 7); $qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $suffix, $f)); + break; + case 'person_address_street_address_1': case 'person_address_street_address_2': case 'person_address_valid_from': @@ -470,77 +378,94 @@ class ReportList implements ListInterface, ExportElementValidatedInterface case 'person_address_country_code': // remove 'person_' $suffix = \substr($f, 7); - + $qb->addSelect(sprintf( 'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s', // get the part after address_ - strtoupper(substr($suffix, 8)), - $f)); + strtoupper(substr($suffix, 8)), + $f + )); $qb->setParameter('address_date', $data['address_date']); + break; + case 'report_scope': $qb->addSelect(sprintf('IDENTITY(report.scope) AS %s', 'report_scope')); + break; + case 'report_user': $qb->addSelect(sprintf('IDENTITY(report.user) AS %s', 'report_user')); + break; + default: $prefix = \substr($f, 0, 7); $suffix = \substr($f, 7); - - switch($prefix) { + + switch ($prefix) { case 'person_': $qb->addSelect(sprintf('person.%s as %s', $suffix, $f)); + break; + case 'report_': $qb->addSelect(sprintf('report.%s as %s', $suffix, $f)); + break; + default: - throw new \LogicException("this prefix $prefix should " - . "not be encountered. Full field: $f"); + throw new LogicException("this prefix {$prefix} should " + . "not be encountered. Full field: {$f}"); } } - } - + // process fields which are custom fields foreach ($this->getCustomFields() as $cf) { // do not add custom fields which are not selected if (!\in_array($cf->getSlug(), $data['fields'])) { continue; } - + $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); - + // if is multiple, split into multiple columns if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { - foreach($cfType->getChoices($cf) as $choiceSlug => $label) { - $slug = $this->slugToDQL($cf->getSlug(), 'choice', [ 'choiceSlug' => $choiceSlug ]); + foreach ($cfType->getChoices($cf) as $choiceSlug => $label) { + $slug = $this->slugToDQL($cf->getSlug(), 'choice', ['choiceSlug' => $choiceSlug]); $qb->addSelect( - sprintf('GET_JSON_FIELD_BY_KEY(report.cFData, :slug%s) AS %s', - $slug, $slug)); + sprintf( + 'GET_JSON_FIELD_BY_KEY(report.cFData, :slug%s) AS %s', + $slug, + $slug + ) + ); $qb->setParameter(sprintf('slug%s', $slug), $cf->getSlug()); } } else { // not multiple, add a single column $slug = $this->slugToDQL($cf->getSlug()); $qb->addSelect( - sprintf('GET_JSON_FIELD_BY_KEY(report.cFData, :slug%s) AS %s', - $slug, $slug)); + sprintf( + 'GET_JSON_FIELD_BY_KEY(report.cFData, :slug%s) AS %s', + $slug, + $slug + ) + ); $qb->setParameter(sprintf('slug%s', $slug), $cf->getSlug()); } } - + $qb - ->from(Report::class, 'report') - ->leftJoin('report.person', 'person') - ->join('person.center', 'center') - ->andWhere($qb->expr()->eq('report.cFGroup', ':cFGroup')) - ->setParameter('cFGroup', $this->customfieldsGroup) - ->andWhere('center IN (:authorized_centers)') - ->setParameter('authorized_centers', $centers); - ; - + ->from(Report::class, 'report') + ->leftJoin('report.person', 'person') + ->join('person.center', 'center') + ->andWhere($qb->expr()->eq('report.cFGroup', ':cFGroup')) + ->setParameter('cFGroup', $this->customfieldsGroup) + ->andWhere('center IN (:authorized_centers)') + ->setParameter('authorized_centers', $centers); + return $qb; } @@ -553,4 +478,114 @@ class ReportList implements ListInterface, ExportElementValidatedInterface { return [Declarations::PERSON_IMPLIED_IN, Declarations::PERSON_TYPE, 'report']; } + + public function validateForm($data, ExecutionContextInterface $context) + { + // get the field starting with address_ + $addressFields = array_filter(function ($el) { + return substr($el, 0, 8) === 'address_'; + }, $this->fields); + + // check if there is one field starting with address in data + if (count(array_intersect($data['fields'], $addressFields)) > 0) { + // if a field address is checked, the date must not be empty + if (empty($data['address_date'])) { + $context + ->buildViolation('You must set this date if an address is checked') + ->atPath('address_date') + ->addViolation(); + } + } + } + + private function DQLToSlug($cleanedSlug) + { + return $this->slugs[$cleanedSlug]['slug']; + } + + /** + * @param mixed $slug + * + * @return an array with keys = 'slug', 'type', 'additionnalInfo' + */ + private function extractInfosFromSlug($slug) + { + return $this->slugs[$slug]; + } + + /** + * Get custom fields associated with person. + * + * @return CustomField[] + */ + private function getCustomFields() + { + return \array_filter($this->customfieldsGroup + ->getCustomFields()->toArray(), function (CustomField $cf) { + return $cf->getType() !== 'title'; + }); + } + + private function getLabelForCustomField($key, array $values, $data) + { + // for fields which are custom fields + /* @var $cf CustomField */ + $cf = $this->em + ->getRepository(CustomField::class) + ->findOneBy(['slug' => $this->DQLToSlug($key)]); + + $cfType = $this->customFieldProvider->getCustomFieldByType($cf->getType()); + $defaultFunction = function ($value) use ($cf) { + if ('_header' === $value) { + return $this->translatableStringHelper->localize($cf->getName()); + } + + return $this->customFieldProvider + ->getCustomFieldByType($cf->getType()) + ->render(json_decode($value, true), $cf, 'csv'); + }; + + if ($cfType instanceof CustomFieldChoice and $cfType->isMultiple($cf)) { + return function ($value) use ($cf, $cfType, $key) { + $slugChoice = $this->extractInfosFromSlug($key)['additionnalInfos']['choiceSlug']; + $decoded = \json_decode($value, true); + + if ('_header' === $value) { + $label = $cfType->getChoices($cf)[$slugChoice]; + + return $this->translatableStringHelper->localize($cf->getName()) + . ' | ' . $label; + } + + if ('_other' === $slugChoice and $cfType->isChecked($cf, $choiceSlug, $decoded)) { + return $cfType->extractOtherValue($cf, $decoded); + } + + return $cfType->isChecked($cf, $slugChoice, $decoded); + }; + } else { + return $defaultFunction; + } + } + + /** + * clean a slug to be usable by DQL. + * + * @param string $type the type of the customfield, if required (currently only for choices) + * @param mixed $slug + * + * @return string + */ + private function slugToDQL($slug, $type = 'default', array $additionalInfos = []) + { + $uid = 'slug_' . uniqid(); + + $this->slugs[$uid] = [ + 'slug' => $slug, + 'type' => $type, + 'additionnalInfos' => $additionalInfos, + ]; + + return $uid; + } } diff --git a/src/Bundle/ChillReportBundle/Export/Export/ReportListProvider.php b/src/Bundle/ChillReportBundle/Export/Export/ReportListProvider.php index e7b8a2a79..6d01cd04a 100644 --- a/src/Bundle/ChillReportBundle/Export/Export/ReportListProvider.php +++ b/src/Bundle/ChillReportBundle/Export/Export/ReportListProvider.php @@ -1,49 +1,46 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\ReportBundle\Export\Export; + +use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\CustomFieldsBundle\Service\CustomFieldProvider; +use Chill\MainBundle\Export\ExportElementsProviderInterface; +use Chill\MainBundle\Templating\TranslatableStringHelper; +use Chill\ReportBundle\Entity\Report; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\Translation\TranslatorInterface; + class ReportListProvider implements ExportElementsProviderInterface { /** - * - * @var EntityManagerInterface - */ - protected $em; - - /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * * @var CustomFieldProvider */ protected $customFieldProvider; - + + /** + * @var EntityManagerInterface + */ + protected $em; + + /** + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + /** - * * @var TranslatorInterface */ protected $translator; - - function __construct( - EntityManagerInterface $em, + + public function __construct( + EntityManagerInterface $em, TranslatableStringHelper $translatableStringHelper, TranslatorInterface $translator, CustomFieldProvider $customFieldProvider @@ -54,24 +51,22 @@ class ReportListProvider implements ExportElementsProviderInterface $this->customFieldProvider = $customFieldProvider; } - - public function getExportElements() { $groups = $this->em->getRepository(CustomFieldsGroup::class) - ->findBy([ 'entity' => Report::class ]) - ; + ->findBy(['entity' => Report::class]); $reports = []; - + foreach ($groups as $group) { $reports[$group->getId()] = new ReportList( - $group, + $group, $this->translatableStringHelper, $this->translator, $this->customFieldProvider, - $this->em); + $this->em + ); } - + return $reports; } } diff --git a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php index 379d9ccda..c3c244957 100644 --- a/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php +++ b/src/Bundle/ChillReportBundle/Export/Filter/ReportDateFilter.php @@ -1,24 +1,21 @@ - */ class ReportDateFilter implements FilterInterface { - public function addRole() { return null; @@ -27,15 +24,18 @@ class ReportDateFilter implements FilterInterface public function alterQuery(\Doctrine\ORM\QueryBuilder $qb, $data) { $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->between('report.date', ':report_date_filter_date_from', - ':report_date_filter_date_to'); + $clause = $qb->expr()->between( + 'report.date', + ':report_date_filter_date_from', + ':report_date_filter_date_to' + ); if ($where instanceof Expr\Andx) { $where->add($clause); } else { $where = $qb->expr()->andX($clause); } - + $qb->add('where', $where); $qb->setParameter('report_date_filter_date_from', $data['date_from']); $qb->setParameter('report_date_filter_date_to', $data['date_to']); @@ -48,24 +48,24 @@ class ReportDateFilter implements FilterInterface public function buildForm(\Symfony\Component\Form\FormBuilderInterface $builder) { - $builder->add('date_from', ChillDateType::class, array( - 'label' => "Report is after this date", - 'data' => new \DateTime(), - )); - - $builder->add('date_to', ChillDateType::class, array( - 'label' => "Report is before this date", - 'data' => new \DateTime(), - )); + $builder->add('date_from', ChillDateType::class, [ + 'label' => 'Report is after this date', + 'data' => new DateTime(), + ]); + + $builder->add('date_to', ChillDateType::class, [ + 'label' => 'Report is before this date', + 'data' => new DateTime(), + ]); } public function describeAction($data, $format = 'string') { - return array('Filtered by report\'s date: ' - . 'between %date_from% and %date_to%', array( + return ['Filtered by report\'s date: ' + . 'between %date_from% and %date_to%', [ '%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() diff --git a/src/Bundle/ChillReportBundle/Form/ReportType.php b/src/Bundle/ChillReportBundle/Form/ReportType.php index d804dd6b8..97af4731a 100644 --- a/src/Bundle/ChillReportBundle/Form/ReportType.php +++ b/src/Bundle/ChillReportBundle/Form/ReportType.php @@ -1,109 +1,97 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Form; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; +use Chill\CustomFieldsBundle\Form\Type\CustomFieldType; use Chill\MainBundle\Form\Type\AppendScopeChoiceTypeTrait; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Form\Extension\Core\Type\DateType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\Persistence\ObjectManager; -use Chill\CustomFieldsBundle\Form\Type\CustomFieldType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; class ReportType extends AbstractType { use AppendScopeChoiceTypeTrait; /** - * * @var AuthorizationHelper */ protected $authorizationHelper; /** - * - * @var TranslatableStringHelper - */ - protected $translatableStringHelper; - - /** - * * @var \Doctrine\Persistence\ObjectManager */ protected $om; /** - * + * @var TranslatableStringHelper + */ + protected $translatableStringHelper; + + /** * @var \Chill\MainBundle\Entity\User */ protected $user; - public function __construct(AuthorizationHelper $helper, + public function __construct( + AuthorizationHelper $helper, TokenStorageInterface $tokenStorage, TranslatableStringHelper $translatableStringHelper, - ObjectManager $om) - { + ObjectManager $om + ) { $this->authorizationHelper = $helper; $this->user = $tokenStorage->getToken()->getUser(); $this->translatableStringHelper = $translatableStringHelper; $this->om = $om; } - /** - * @param FormBuilderInterface $builder - * @param array $options - */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('user') - ->add('date', DateType::class, - array('required' => true, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy')) - ->add('cFData', CustomFieldType::class, - array('attr' => array('class' => 'cf-fields'), - 'group' => $options['cFGroup'])) - ; + ->add( + 'date', + DateType::class, + ['required' => true, 'widget' => 'single_text', 'format' => 'dd-MM-yyyy'] + ) + ->add( + 'cFData', + CustomFieldType::class, + ['attr' => ['class' => 'cf-fields'], + 'group' => $options['cFGroup'], ] + ); - $this->appendScopeChoices($builder, $options['role'], $options['center'], - $this->user, $this->authorizationHelper, - $this->translatableStringHelper, - $this->om); + $this->appendScopeChoices( + $builder, + $options['role'], + $options['center'], + $this->user, + $this->authorizationHelper, + $this->translatableStringHelper, + $this->om + ); } - /** - * @param OptionsResolver $resolver - */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ReportBundle\Entity\Report' - )); + $resolver->setDefaults([ + 'data_class' => 'Chill\ReportBundle\Entity\Report', + ]); - $resolver->setRequired(array( + $resolver->setRequired([ 'cFGroup', - )); + ]); $resolver->setAllowedTypes('cFGroup', 'Chill\CustomFieldsBundle\Entity\CustomFieldsGroup'); diff --git a/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/AppKernel.php b/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/AppKernel.php index 4222efe69..a2293aa3c 100644 --- a/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/AppKernel.php +++ b/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/AppKernel.php @@ -1,13 +1,36 @@ load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); - } - - /** - * @return string - */ - public function getCacheDir() - { - return sys_get_temp_dir().'/ChillReportBundle/cache'; - } - - /** - * @return string - */ - public function getLogDir() - { - return sys_get_temp_dir().'/ChillReportBundle/logs'; + $loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml'); } } diff --git a/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/autoload.php b/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/autoload.php index 39dc0e2ba..a2dfe7f92 100644 --- a/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/autoload.php +++ b/src/Bundle/ChillReportBundle/Resources/test/Fixtures/App/app/autoload.php @@ -1,11 +1,18 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Search; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Search\AbstractSearch; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Chill\MainBundle\Search\ParsingException; -use Doctrine\ORM\QueryBuilder; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\QueryBuilder; +use RuntimeException; +use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Chill\MainBundle\Entity\Scope; /** - * Search amongst reports - * - * @author Julien Fastré + * Search amongst reports. */ class ReportSearch extends AbstractSearch implements ContainerAwareInterface { use \Symfony\Component\DependencyInjection\ContainerAwareTrait; - + /** * @var EntityManagerInterface */ private $em; - + /** - * * @var AuthorizationHelper */ private $helper; - + /** - * * @var \Chill\MainBundle\Entity\User */ private $user; - - public function __construct(EntityManagerInterface $em, - AuthorizationHelper $helper, TokenStorageInterface $tokenStorage) - { + + public function __construct( + EntityManagerInterface $em, + AuthorizationHelper $helper, + TokenStorageInterface $tokenStorage + ) { $this->em = $em; $this->helper = $helper; - - if(! $tokenStorage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) { - throw new \RuntimeException('an user must be associated with token'); + + if (!$tokenStorage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) { + throw new RuntimeException('an user must be associated with token'); } $this->user = $tokenStorage->getToken()->getUser(); } @@ -78,109 +66,105 @@ class ReportSearch extends AbstractSearch implements ContainerAwareInterface return false; } - public function renderResult(array $terms, $start = 0, $limit = 50, array $options = array(), $format = 'html') + public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html') { - return $this->container->get('templating')->render('ChillReportBundle:Search:results.html.twig', array( + return $this->container->get('templating')->render('ChillReportBundle:Search:results.html.twig', [ 'reports' => $this->getReports($terms, $start, $limit), 'total' => $this->count($terms), - 'pattern' => $this->recomposePattern($terms, array( 'date'), 'report') - )); - } - - private function getReports(array $terms, $start, $limit) - { - $qb = $this->buildQuery($terms); - - $qb->select('r') - ->setMaxResults($limit) - ->setFirstResult($start) - ->orderBy('r.date', 'desc') - ; - - $reportQuery = $qb->getQuery(); - $reportQuery->setFetchMode("Chill\ReportBundle\Entity\Report", "person", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER); - - return $reportQuery->getResult(); - } - - private function count(array $terms) - { - $qb = $this->buildQuery($terms); - - $qb->select('COUNT(r.id)'); - - return $qb->getQuery()->getSingleScalarResult(); - } - - - /** - * @param array $terms the terms - * @return \Doctrine\ORM\QueryBuilder - */ - private function buildQuery(array $terms) - { - - $query = $this->em->createQueryBuilder(); - - $query->from('ChillReportBundle:Report', 'r'); - - //throw a parsing exception if key 'date' and default is set - if (array_key_exists('date', $terms) && $terms['_default'] !== '') { - throw new ParsingException('You may not set a date argument and a date in default'); - } - //throw a parsing exception if no argument except report - if (!array_key_exists('date', $terms) && $terms['_default'] === '') { - throw new ParsingException('You must provide either a date:YYYY-mm-dd argument or a YYYY-mm-dd default search'); - } - - - if (array_key_exists('date', $terms)) { - $query->andWhere($query->expr()->eq('r.date', ':date')) - ->setParameter('date', $this->parseDate($terms['date'])) - ; - } elseif (array_key_exists('_default', $terms)) { - $query->andWhere($query->expr()->eq('r.date', ':date')) - ->setParameter('date', $this->parseDate($terms['_default'])) - ; - } - - $query->andWhere($this->addACL($query)); - - return $query; - } - - private function addACL(QueryBuilder $qb) - { - //adding join - $qb->join('r.person', 'p'); - - $role = new Role('CHILL_REPORT_SEE'); - $reachableCenters = $this->helper->getReachableCenters($this->user, $role); - - $whereElement = $qb->expr()->orX(); - $i = 0; - foreach ($reachableCenters as $center) { - $reachableScopesId = array_map( - function (Scope $scope) { return $scope->getId(); }, - $this->helper->getReachableScopes($this->user, $role, $center) - ); - $whereElement->add( - $qb->expr()->andX( - $qb->expr()->eq('p.center', ':center_'.$i), - $qb->expr()->in('r.scope', ':reachable_scopes_'.$i) - ) - ) - ; - $qb->setParameter('center_'.$i, $center); - $qb->setParameter('reachable_scopes_'.$i, $reachableScopesId); - } - - return $whereElement; + 'pattern' => $this->recomposePattern($terms, ['date'], 'report'), + ]); } public function supports($domain, $format = 'html') { - return $domain === 'report'; + return 'report' === $domain; } + private function addACL(QueryBuilder $qb) + { + //adding join + $qb->join('r.person', 'p'); + + $role = new Role('CHILL_REPORT_SEE'); + $reachableCenters = $this->helper->getReachableCenters($this->user, $role); + + $whereElement = $qb->expr()->orX(); + $i = 0; + + foreach ($reachableCenters as $center) { + $reachableScopesId = array_map( + function (Scope $scope) { + return $scope->getId(); + }, + $this->helper->getReachableScopes($this->user, $role, $center) + ); + $whereElement->add( + $qb->expr()->andX( + $qb->expr()->eq('p.center', ':center_' . $i), + $qb->expr()->in('r.scope', ':reachable_scopes_' . $i) + ) + ); + $qb->setParameter('center_' . $i, $center); + $qb->setParameter('reachable_scopes_' . $i, $reachableScopesId); + } + + return $whereElement; + } + + /** + * @param array $terms the terms + * + * @return \Doctrine\ORM\QueryBuilder + */ + private function buildQuery(array $terms) + { + $query = $this->em->createQueryBuilder(); + + $query->from('ChillReportBundle:Report', 'r'); + + //throw a parsing exception if key 'date' and default is set + if (array_key_exists('date', $terms) && '' !== $terms['_default']) { + throw new ParsingException('You may not set a date argument and a date in default'); + } + //throw a parsing exception if no argument except report + if (!array_key_exists('date', $terms) && '' === $terms['_default']) { + throw new ParsingException('You must provide either a date:YYYY-mm-dd argument or a YYYY-mm-dd default search'); + } + + if (array_key_exists('date', $terms)) { + $query->andWhere($query->expr()->eq('r.date', ':date')) + ->setParameter('date', $this->parseDate($terms['date'])); + } elseif (array_key_exists('_default', $terms)) { + $query->andWhere($query->expr()->eq('r.date', ':date')) + ->setParameter('date', $this->parseDate($terms['_default'])); + } + + $query->andWhere($this->addACL($query)); + + return $query; + } + + private function count(array $terms) + { + $qb = $this->buildQuery($terms); + + $qb->select('COUNT(r.id)'); + + return $qb->getQuery()->getSingleScalarResult(); + } + + private function getReports(array $terms, $start, $limit) + { + $qb = $this->buildQuery($terms); + + $qb->select('r') + ->setMaxResults($limit) + ->setFirstResult($start) + ->orderBy('r.date', 'desc'); + + $reportQuery = $qb->getQuery(); + $reportQuery->setFetchMode('Chill\\ReportBundle\\Entity\\Report', 'person', \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER); + + return $reportQuery->getResult(); + } } diff --git a/src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php b/src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php index 5741b567b..ce731378e 100644 --- a/src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php +++ b/src/Bundle/ChillReportBundle/Security/Authorization/ReportVoter.php @@ -1,92 +1,78 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Security\Authorization; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Security\Authorization\AbstractChillVoter; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\ReportBundle\Entity\Report; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Center; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use function in_array; -/** - * - * - * @author Julien Fastré - */ class ReportVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_REPORT_CREATE'; - const SEE = 'CHILL_REPORT_SEE'; - const UPDATE = 'CHILL_REPORT_UPDATE'; - const LISTS = 'CHILL_REPORT_LISTS'; + public const CREATE = 'CHILL_REPORT_CREATE'; + + public const LISTS = 'CHILL_REPORT_LISTS'; + + public const SEE = 'CHILL_REPORT_SEE'; + + public const UPDATE = 'CHILL_REPORT_UPDATE'; /** - * * @var AuthorizationHelper */ protected $helper; - public function __construct(AuthorizationHelper $helper) { $this->helper = $helper; } + public function getRoles() + { + return [self::CREATE, self::UPDATE, self::SEE, self::LISTS]; + } + + public function getRolesWithHierarchy() + { + return ['Report' => $this->getRoles()]; + } + + public function getRolesWithoutScope() + { + return [self::LISTS]; + } protected function supports($attribute, $subject) { if ($subject instanceof Report) { - return \in_array($attribute, [ - self::CREATE, self::UPDATE, self::SEE + return in_array($attribute, [ + self::CREATE, self::UPDATE, self::SEE, ]); - } elseif ($subject instanceof Center) { - return $attribute === self::LISTS; + } + + if ($subject instanceof Center) { + return self::LISTS === $attribute; } } - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) { if (!$token->getUser() instanceof User) { return false; } + return $this->helper->userHasAccess($token->getUser(), $subject, $attribute); } - - - public function getRoles() - { - return [self::CREATE, self::UPDATE, self::SEE, self::LISTS]; - } - - public function getRolesWithoutScope() - { - return array(self::LISTS); - } - - public function getRolesWithHierarchy() - { - return [ 'Report' => $this->getRoles() ]; - } } diff --git a/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerNextTest.php b/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerNextTest.php index e3c96bf22..0030b2444 100644 --- a/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerNextTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerNextTest.php @@ -1,178 +1,188 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Chill\PersonBundle\Entity\Person; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; +use Chill\PersonBundle\Entity\Person; +use DateTime; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\BrowserKit\Client; /** * This class is much well writtend than ReportControllerTest class, and will * replace ReportControllerTest in the future. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ReportControllerNextTest extends WebTestCase { /** - * - * @var Person - */ - protected $person; - - /** - * * @var CustomFieldsGroup */ protected $group; - - + + /** + * @var Person + */ + protected $person; + public function setUp() { static::bootKernel(); // get person from fixture $em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - + ->get('doctrine.orm.entity_manager'); + $this->person = $em - ->getRepository('ChillPersonBundle:Person') - ->findOneBy(array( - 'lastName' => 'Charline', - 'firstName' => 'Depardieu' - ) - ); - - if ($this->person === NULL) { - throw new \RuntimeException("The expected person is not present in the database. " - . "Did you run `php app/console doctrine:fixture:load` before launching tests ? " + ->getRepository('ChillPersonBundle:Person') + ->findOneBy( + [ + 'lastName' => 'Charline', + 'firstName' => 'Depardieu', + ] + ); + + if (null === $this->person) { + throw new RuntimeException('The expected person is not present in the database. ' + . 'Did you run `php app/console doctrine:fixture:load` before launching tests ? ' . "(expecting person is 'Charline Depardieu'"); } - + // get custom fields group from fixture $customFieldsGroups = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->findBy(array('entity' => 'Chill\ReportBundle\Entity\Report')) - ; + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->findBy(['entity' => 'Chill\ReportBundle\Entity\Report']); //filter customFieldsGroup to get only "situation de logement" - $filteredCustomFieldsGroupHouse = array_filter($customFieldsGroups, - function(CustomFieldsGroup $group) { - return in_array("Situation de logement", $group->getName()); - }); + $filteredCustomFieldsGroupHouse = array_filter( + $customFieldsGroups, + function (CustomFieldsGroup $group) { + return in_array('Situation de logement', $group->getName()); + } + ); $this->group = $filteredCustomFieldsGroupHouse[0]; } - - public function testValidCreate() - { - $client = $this->getAuthenticatedClient(); - $form = $this->getReportForm($this->person, $this->group, $client); - - $form->get('chill_reportbundle_report[date]')->setValue( - (new \DateTime())->format('d-m-Y')); - - $client->submit($form); - - $this->assertTrue($client->getResponse()->isRedirect(), - "The next page is a redirection to the new report's view page"); - - } - + public function testUngrantedUserIsDeniedAccessOnListReports() { $client = $this->getAuthenticatedClient('center b_social'); - $client->request('GET', sprintf('/fr/person/%d/report/list', - $this->person->getId())); - - $this->assertEquals(403, $client->getResponse()->getStatusCode(), - 'assert that user for center b has a 403 status code when listing' - . 'reports on person from center a'); + $client->request('GET', sprintf( + '/fr/person/%d/report/list', + $this->person->getId() + )); + + $this->assertEquals( + 403, + $client->getResponse()->getStatusCode(), + 'assert that user for center b has a 403 status code when listing' + . 'reports on person from center a' + ); } - + public function testUngrantedUserIsDeniedAccessOnReport() { $client = $this->getAuthenticatedClient('center b_social'); $reports = static::$kernel->getContainer()->get('doctrine.orm.entity_manager') - ->getRepository('ChillReportBundle:Report') - ->findBy(array('person' => $this->person)); + ->getRepository('ChillReportBundle:Report') + ->findBy(['person' => $this->person]); $report = $reports[0]; - - $client->request('GET', sprintf('/fr/person/%d/report/%d/view', - $this->person->getId(), $report->getId())); - - $this->assertEquals(403, $client->getResponse()->getStatusCode(), - 'assert that user for center b has a 403 status code when ' - . 'trying to watch a report from person from center a'); + + $client->request('GET', sprintf( + '/fr/person/%d/report/%d/view', + $this->person->getId(), + $report->getId() + )); + + $this->assertEquals( + 403, + $client->getResponse()->getStatusCode(), + 'assert that user for center b has a 403 status code when ' + . 'trying to watch a report from person from center a' + ); } - - public function testUngrantedUserIsDeniedReportNew() - { - $client = $this->getAuthenticatedClient('center b_social'); - - $client->request('GET', sprintf('fr/person/%d/report/cfgroup/%d/new', - $this->person->getId(), $this->group->getId())); - - $this->assertEquals(403, $client->getResponse()->getStatusCode(), - 'assert that user is denied on trying to show a form "new" for' - . ' a person on another center'); - } - + public function testUngrantedUserIsDeniedReportCreate() { $clientCenterA = $this->getAuthenticatedClient('center a_social'); - + $form = $this->getReportForm($this->person, $this->group, $clientCenterA); - + $clientCenterB = $this->getAuthenticatedClient('center b_social'); $clientCenterB->submit($form); - - $this->assertEquals(403, $clientCenterB->getResponse()->getStatusCode(), - 'assert that user is denied on trying to show a form "new" for' - . ' a person on another center'); + + $this->assertEquals( + 403, + $clientCenterB->getResponse()->getStatusCode(), + 'assert that user is denied on trying to show a form "new" for' + . ' a person on another center' + ); } - + + public function testUngrantedUserIsDeniedReportNew() + { + $client = $this->getAuthenticatedClient('center b_social'); + + $client->request('GET', sprintf( + 'fr/person/%d/report/cfgroup/%d/new', + $this->person->getId(), + $this->group->getId() + )); + + $this->assertEquals( + 403, + $client->getResponse()->getStatusCode(), + 'assert that user is denied on trying to show a form "new" for' + . ' a person on another center' + ); + } + + public function testValidCreate() + { + $client = $this->getAuthenticatedClient(); + $form = $this->getReportForm($this->person, $this->group, $client); + + $form->get('chill_reportbundle_report[date]')->setValue( + (new DateTime())->format('d-m-Y') + ); + + $client->submit($form); + + $this->assertTrue( + $client->getResponse()->isRedirect(), + "The next page is a redirection to the new report's view page" + ); + } + protected function getAuthenticatedClient($username = 'center a_social') { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => 'password', - )); + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => 'password', + ]); } - + /** - * - * @param Person $person - * @param CustomFieldsGroup $group - * @param Client $client * @return \Symfony\Component\DomCrawler\Form */ protected function getReportForm(Person $person, CustomFieldsGroup $group, Client $client) { - $url = sprintf('fr/person/%d/report/cfgroup/%d/new', $person->getId(), - $group->getId()); + $url = sprintf( + 'fr/person/%d/report/cfgroup/%d/new', + $person->getId(), + $group->getId() + ); $crawler = $client->request('GET', $url); - + return $crawler->selectButton('Ajouter le rapport') - ->form(); + ->form(); } - - - } diff --git a/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerTest.php b/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerTest.php index d7bf25f06..4aa6d871b 100644 --- a/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Controller/ReportControllerTest.php @@ -1,290 +1,300 @@ , - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Tests\Controller; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; -use Symfony\Component\DomCrawler\Form; -use Symfony\Component\DomCrawler\Link; -use Symfony\Component\DomCrawler\Crawler; use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup; use Chill\PersonBundle\Entity\Person; +use DateTime; +use RuntimeException; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Form; +use Symfony\Component\DomCrawler\Link; /** - * Test the life cycles of controllers, according to - * https://redmine.champs-libres.coop/projects/report/wiki/Test_plan_for_report_lifecycle + * Test the life cycles of controllers, according to + * https://redmine.champs-libres.coop/projects/report/wiki/Test_plan_for_report_lifecycle. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ReportControllerTest extends WebTestCase { - - const REPORT_NAME_FIELD = 'cFGroup'; - + public const REPORT_NAME_FIELD = 'cFGroup'; + /** - * - * @var \Chill\PersonBundle\Entity\Person - */ - private static $person; - - /** - * * @var \SClientymfony\Component\BrowserKit\ */ private static $client; - - private static $user; - + /** - * - * @var CustomFieldsGroup - */ - private static $group; - - /** - * * @var \Doctrine\ORM\EntityManagerInterface */ private static $em; + /** + * @var CustomFieldsGroup + */ + private static $group; + + /** + * @var \Chill\PersonBundle\Entity\Person + */ + private static $person; + + private static $user; + public static function setUpBeforeClass() { static::bootKernel(); - + static::$em = static::$kernel->getContainer() ->get('doctrine.orm.entity_manager'); //get a random person static::$person = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillPersonBundle:Person') - ->findOneBy(array( - 'lastName' => 'Charline', - 'firstName' => 'Depardieu' - ) - ); - - if (static::$person === NULL) { - throw new \RuntimeException("The expected person is not present in the database. " - . "Did you run `php app/console doctrine:fixture:load` before launching tests ? " + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillPersonBundle:Person') + ->findOneBy( + [ + 'lastName' => 'Charline', + 'firstName' => 'Depardieu', + ] + ); + + if (null === static::$person) { + throw new RuntimeException('The expected person is not present in the database. ' + . 'Did you run `php app/console doctrine:fixture:load` before launching tests ? ' . "(expecting person is 'Charline Depardieu'"); } - + $customFieldsGroups = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->findBy(array('entity' => 'Chill\ReportBundle\Entity\Report')) - ; + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->findBy(['entity' => 'Chill\ReportBundle\Entity\Report']); //filter customFieldsGroup to get only "situation de logement" - $filteredCustomFieldsGroupHouse = array_filter($customFieldsGroups, - function(CustomFieldsGroup $group) { - return in_array("Situation de logement", $group->getName()); - }); + $filteredCustomFieldsGroupHouse = array_filter( + $customFieldsGroups, + function (CustomFieldsGroup $group) { + return in_array('Situation de logement', $group->getName()); + } + ); static::$group = $filteredCustomFieldsGroupHouse[0]; - - static::$user = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillMainBundle:User') - ->findOneBy(array('username' => "center a_social")); + + static::$user = static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillMainBundle:User') + ->findOneBy(['username' => 'center a_social']); } - - public function setUp() + + public function setUp() { - static::$client = static::createClient(array(), array( - 'PHP_AUTH_USER' => 'center a_social', - 'PHP_AUTH_PW' => 'password', - )); + static::$client = static::createClient([], [ + 'PHP_AUTH_USER' => 'center a_social', + 'PHP_AUTH_PW' => 'password', + ]); } - + /** - * * @param type $username + * * @return Client */ public function getAuthenticatedClient($username = 'center a_social') { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => 'password', - )); + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => 'password', + ]); } - + + /** + * @return type + * @depends testMenu + */ + public function testChooseReportModelPage(Link $link) + { + // When I click on "add a report" link in menu + $client = $this->getAuthenticatedClient(); + $crawlerAddAReportPage = $client->click($link); + + $form = $crawlerAddAReportPage->selectButton('Créer un nouveau rapport')->form(); + + $this->assertInstanceOf( + 'Symfony\Component\DomCrawler\Form', + $form, + 'I can see a form with a button "add a new report" ' + ); + + $this->assertGreaterThan( + 1, + count($form->get(self::REPORT_NAME_FIELD) + ->availableOptionValues()), + 'I can choose between report models' + ); + + $possibleOptionsValue = $form->get(self::REPORT_NAME_FIELD) + ->availableOptionValues(); + $form->get(self::REPORT_NAME_FIELD)->setValue( + $possibleOptionsValue[array_rand($possibleOptionsValue)] + ); + + $client->submit($form); + + $this->assertTrue($client->getResponse()->isRedirect()); + + return $client->followRedirect(); + } + + /** + * Test that setting a Null date redirect to an error page. + * + * @depends testNewReportPage + */ + public function testInvalidDate(Form $form) + { + $client = $this->getAuthenticatedClient(); + $this->markTestSkipped('This test raise an error since symfony 2.7. ' + . 'The user is not correctly reloaded from database.'); + $filledForm = $this->fillCorrectForm($form); + $filledForm->get('chill_reportbundle_report[date]')->setValue('invalid date value'); + + $crawler = $client->submit($filledForm); + + $this->assertFalse($client->getResponse()->isRedirect()); + $this->assertGreaterThan(0, $crawler->filter('.error')->count()); + } + + /** + * Test that a incorrect value in user will show an error page. + * + * @depends testNewReportPage + */ + public function testInvalidUser(Form $form) + { + $client = $this->getAuthenticatedClient(); + $filledForm = $this->fillCorrectForm($form); + $select = $filledForm->get('chill_reportbundle_report[user]') + ->disableValidation() + ->setValue(-1); + + $crawler = $client->submit($filledForm); + + $this->assertFalse($client->getResponse()->isRedirect()); + $this->assertGreaterThan(0, $crawler->filter('.error')->count()); + } + + /** + * @depends testValidCreate + * + * @param int $reportId + */ + public function testList($reportId) + { + $client = $this->getAuthenticatedClient(); + $crawler = $client->request('GET', sprintf( + '/fr/person/%s/report/list', + static::$person->getId() + )); + + $this->assertTrue($client->getResponse()->isSuccessful()); + + $linkSee = $crawler->filter('.bt-view')->links(); + $this->assertGreaterThan(0, count($linkSee)); + $this->assertRegExp(sprintf( + '|/fr/person/%s/report/[0-9]*/view$|', + static::$person->getId(), + $reportId + ), $linkSee[0]->getUri()); + + $linkUpdate = $crawler->filter('.bt-update')->links(); + $this->assertGreaterThan(0, count($linkUpdate)); + $this->assertRegExp(sprintf( + '|/fr/person/%s/report/[0-9]*/edit$|', + static::$person->getId(), + $reportId + ), $linkUpdate[0]->getUri()); + } + /** * Set up the browser to be at a random person general page (/fr/person/%d/general), - * check if there is a menu link for adding a new report and return this link (as producer) - * - * We assume that : + * check if there is a menu link for adding a new report and return this link (as producer). + * + * We assume that : * - we are on a "person" page * - there are more than one report model - * */ public function testMenu() { $client = $this->getAuthenticatedClient(); - $crawlerPersonPage = $client->request('GET', sprintf('/fr/person/%d/general', - static::$person->getId())); - - if (! $client->getResponse()->isSuccessful()) { + $crawlerPersonPage = $client->request('GET', sprintf( + '/fr/person/%d/general', + static::$person->getId() + )); + + if (!$client->getResponse()->isSuccessful()) { var_dump($crawlerPersonPage->html()); - throw new \RuntimeException('the request at person page failed'); + + throw new RuntimeException('the request at person page failed'); } - + $link = $crawlerPersonPage->selectLink("AJOUT D'UN RAPPORT")->link(); - $this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $link, - "There is a \"add a report\" link in menu"); - $this->assertContains(sprintf("/fr/person/%d/report/select/type/for/creation", - static::$person->getId()), $link->getUri(), - "There is a \"add a report\" link in menu"); - + $this->assertInstanceOf( + 'Symfony\Component\DomCrawler\Link', + $link, + 'There is a "add a report" link in menu' + ); + $this->assertContains( + sprintf( + '/fr/person/%d/report/select/type/for/creation', + static::$person->getId() + ), + $link->getUri(), + 'There is a "add a report" link in menu' + ); + return $link; } - - /** - * - * @param \Symfony\Component\DomCrawler\Link $link - * @return type - * @depends testMenu - */ - public function testChooseReportModelPage(Link $link) - { - // When I click on "add a report" link in menu - $client = $this->getAuthenticatedClient(); - $crawlerAddAReportPage = $client->click($link); - - $form = $crawlerAddAReportPage->selectButton("Créer un nouveau rapport")->form(); - - $this->assertInstanceOf('Symfony\Component\DomCrawler\Form', $form, - 'I can see a form with a button "add a new report" '); - - $this->assertGreaterThan(1, count($form->get(self::REPORT_NAME_FIELD) - ->availableOptionValues()), - "I can choose between report models"); - $possibleOptionsValue = $form->get(self::REPORT_NAME_FIELD) - ->availableOptionValues(); - $form->get(self::REPORT_NAME_FIELD)->setValue( - $possibleOptionsValue[array_rand($possibleOptionsValue)]); - - $client->submit($form); - - $this->assertTrue($client->getResponse()->isRedirect()); - return $client->followRedirect(); - } - /** - * - * @param \Symfony\Component\DomCrawler\Crawler $crawlerNewReportPage * @return type * @depends testChooseReportModelPage */ public function testNewReportPage(Crawler $crawlerNewReportPage) - { - + { $addForm = $crawlerNewReportPage - ->selectButton('Ajouter le rapport') - ->form(); - - $this->assertInstanceOf('Symfony\Component\DomCrawler\Form', $addForm, - 'I have a report form'); - + ->selectButton('Ajouter le rapport') + ->form(); + + $this->assertInstanceOf( + 'Symfony\Component\DomCrawler\Form', + $addForm, + 'I have a report form' + ); + $this->isFormAsExpected($addForm); - + return $addForm; } - + /** - * get a form for report new - * - * @param \Chill\ReportBundle\Tests\Controller\Person $person - * @param CustomFieldsGroup $group - * @param \Symfony\Component\BrowserKit\Client $client - * @return Form - */ - protected function getReportForm(Person $person, CustomFieldsGroup $group, - \Symfony\Component\BrowserKit\Client $client) - { - $url = sprintf('fr/person/%d/report/cfgroup/%d/new', $person->getId(), - $group->getId()); - $crawler = $client->request('GET', $url); - - return $crawler->selectButton('Ajouter le rapport') - ->form(); - } - - /** - * Test the expected field are present - * - * @param Form $form - * @param boolean $isDefault if the form should be at default values - * - */ - private function isFormAsExpected(Form $form, $isDefault = true) - { - $this->assertTrue($form->has('chill_reportbundle_report[date]'), - 'the report form have a field "date"' ); - $this->assertTrue($form->has('chill_reportbundle_report[user]'), - 'the report form have field "user" '); - - $this->assertEquals('select', $form->get('chill_reportbundle_report[user]') - ->getType(), "the user field is a select input"); - - if ($isDefault) { - $date = new \DateTime('now'); - $this->assertEquals( - $date->format('d-m-Y'), - $form->get('chill_reportbundle_report[date]')->getValue(), - "the date field contains the current date by default" - ); - - //resolve the user - $userId = $form->get('chill_reportbundle_report[user]')->getValue(); - - $this->assertEquals('center a_social', static::$user->getUsername(), - "the user field is the current user by default"); - } - } - - /** - * fill the form with correct data - * - * @param Form $form - */ - private function fillCorrectForm(Form $form) - { - $form->get('chill_reportbundle_report[date]')->setValue( - (new \DateTime())->format('d-m-Y')); - - return $form; - } - - /** - * Test that setting a Null date redirect to an error page - * + * Test that setting a Null date redirect to an error page. */ public function testNullDate() { $client = $this->getAuthenticatedClient(); - $form = $this->getReportForm(static::$person, static::$group, - $client); + $form = $this->getReportForm( + static::$person, + static::$group, + $client + ); //var_dump($form); $filledForm = $this->fillCorrectForm($form); $filledForm->get('chill_reportbundle_report[date]')->setValue(''); @@ -294,50 +304,52 @@ class ReportControllerTest extends WebTestCase $this->assertFalse($client->getResponse()->isRedirect()); $this->assertGreaterThan(0, $crawler->filter('.error')->count()); } - + /** - * Test that setting a Null date redirect to an error page - * - * @param Form $form - * @depends testNewReportPage + * test the update form. + * + * @depends testValidCreate + * + * @param int $reportId */ - public function testInvalidDate(Form $form) + public function testUpdate($reportId) { $client = $this->getAuthenticatedClient(); - $this->markTestSkipped("This test raise an error since symfony 2.7. " - . "The user is not correctly reloaded from database."); - $filledForm = $this->fillCorrectForm($form); - $filledForm->get('chill_reportbundle_report[date]')->setValue('invalid date value'); - - $crawler = $client->submit($filledForm); - - $this->assertFalse($client->getResponse()->isRedirect()); - $this->assertGreaterThan(0, $crawler->filter('.error')->count()); + $crawler = $client->request( + 'GET', + sprintf('/fr/person/%s/report/%s/edit', static::$person->getId(), $reportId) + ); + + $this->assertTrue($client->getResponse()->isSuccessful()); + + $form = $crawler + ->selectButton('Enregistrer le rapport') + ->form(); + + $form->get('chill_reportbundle_report[date]')->setValue( + (new DateTime('yesterday'))->format('d-m-Y') + ); + + $client->submit($form); + + $this->assertTrue($client->getResponse()->isRedirect( + sprintf( + '/fr/person/%s/report/%s/view', + static::$person->getId(), + $reportId + ) + )); + + $this->assertEquals(new DateTime('yesterday'), static::$kernel->getContainer() + ->get('doctrine.orm.entity_manager') + ->getRepository('ChillReportBundle:Report') + ->find($reportId) + ->getDate()); } - + /** - * Test that a incorrect value in user will show an error page - * - * @depends testNewReportPage - * @param Form $form - */ - public function testInvalidUser(Form $form) - { - $client = $this->getAuthenticatedClient(); - $filledForm = $this->fillCorrectForm($form); - $select = $filledForm->get('chill_reportbundle_report[user]') - ->disableValidation() - ->setValue(-1); - - $crawler = $client->submit($filledForm); - - $this->assertFalse($client->getResponse()->isRedirect()); - $this->assertGreaterThan(0, $crawler->filter('.error')->count()); - } - - /** - * Test the creation of a report - * + * Test the creation of a report. + * * depends testNewReportPage * param Form $form */ @@ -349,95 +361,120 @@ class ReportControllerTest extends WebTestCase $addForm = $this->getReportForm(self::$person, self::$group, $client); $filledForm = $this->fillCorrectForm($addForm); $c = $client->submit($filledForm); - - $this->assertTrue($client->getResponse()->isRedirect(), - "The next page is a redirection to the new report's view page"); + + $this->assertTrue( + $client->getResponse()->isRedirect(), + "The next page is a redirection to the new report's view page" + ); $client->followRedirect(); - - $this->assertRegExp("|/fr/person/".static::$person->getId()."/report/[0-9]*/view$|", - $client->getHistory()->current()->getUri(), - "The next page is a redirection to the new report's view page"); - - $matches = array(); - preg_match('|/report/([0-9]*)/view$|', - $client->getHistory()->current()->getUri(), $matches); + + $this->assertRegExp( + '|/fr/person/' . static::$person->getId() . '/report/[0-9]*/view$|', + $client->getHistory()->current()->getUri(), + "The next page is a redirection to the new report's view page" + ); + + $matches = []; + preg_match( + '|/report/([0-9]*)/view$|', + $client->getHistory()->current()->getUri(), + $matches + ); return $matches[1]; } - /** + * Test the view of a report. + * * @depends testValidCreate - * @param int $reportId - */ - public function testList($reportId) - { - $client = $this->getAuthenticatedClient(); - $crawler = $client->request('GET', sprintf('/fr/person/%s/report/list', - static::$person->getId())); - - $this->assertTrue($client->getResponse()->isSuccessful()); - - $linkSee = $crawler->filter('.bt-view')->links(); - $this->assertGreaterThan(0, count($linkSee)); - $this->assertRegExp(sprintf('|/fr/person/%s/report/[0-9]*/view$|', - static::$person->getId(), $reportId), $linkSee[0]->getUri()); - - $linkUpdate = $crawler->filter('.bt-update')->links(); - $this->assertGreaterThan(0, count($linkUpdate)); - $this->assertRegExp(sprintf('|/fr/person/%s/report/[0-9]*/edit$|', - static::$person->getId(), $reportId), $linkUpdate[0]->getUri()); - - } - - /** - * Test the view of a report - * - * @depends testValidCreate + * * @param int $reportId */ public function testView($reportId) { $client = $this->getAuthenticatedClient(); - $client->request('GET', - sprintf('/fr/person/%s/report/%s/view', static::$person->getId(), $reportId)); - - $this->assertTrue($client->getResponse()->isSuccessful(), - 'the page is shown'); + $client->request( + 'GET', + sprintf('/fr/person/%s/report/%s/view', static::$person->getId(), $reportId) + ); + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'the page is shown' + ); } - + /** - * test the update form - * - * @depends testValidCreate - * @param int $reportId + * get a form for report new. + * + * @param \Chill\ReportBundle\Tests\Controller\Person $person + * + * @return Form */ - public function testUpdate($reportId) - { - $client = $this->getAuthenticatedClient(); - $crawler = $client->request('GET', - sprintf('/fr/person/%s/report/%s/edit', static::$person->getId(), $reportId)); - - $this->assertTrue($client->getResponse()->isSuccessful()); - - $form = $crawler - ->selectButton('Enregistrer le rapport') - ->form(); - - $form->get('chill_reportbundle_report[date]')->setValue( - (new \DateTime('yesterday'))->format('d-m-Y')); - - $client->submit($form); - - $this->assertTrue($client->getResponse()->isRedirect( - sprintf('/fr/person/%s/report/%s/view', - static::$person->getId(), $reportId))); + protected function getReportForm( + Person $person, + CustomFieldsGroup $group, + \Symfony\Component\BrowserKit\Client $client + ) { + $url = sprintf( + 'fr/person/%d/report/cfgroup/%d/new', + $person->getId(), + $group->getId() + ); + $crawler = $client->request('GET', $url); - $this->assertEquals(new \DateTime('yesterday'), static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager') - ->getRepository('ChillReportBundle:Report') - ->find($reportId) - ->getDate()); + return $crawler->selectButton('Ajouter le rapport') + ->form(); } + /** + * fill the form with correct data. + */ + private function fillCorrectForm(Form $form) + { + $form->get('chill_reportbundle_report[date]')->setValue( + (new DateTime())->format('d-m-Y') + ); + + return $form; + } + + /** + * Test the expected field are present. + * + * @param bool $isDefault if the form should be at default values + */ + private function isFormAsExpected(Form $form, $isDefault = true) + { + $this->assertTrue( + $form->has('chill_reportbundle_report[date]'), + 'the report form have a field "date"' + ); + $this->assertTrue( + $form->has('chill_reportbundle_report[user]'), + 'the report form have field "user" ' + ); + + $this->assertEquals('select', $form->get('chill_reportbundle_report[user]') + ->getType(), 'the user field is a select input'); + + if ($isDefault) { + $date = new DateTime('now'); + $this->assertEquals( + $date->format('d-m-Y'), + $form->get('chill_reportbundle_report[date]')->getValue(), + 'the date field contains the current date by default' + ); + + //resolve the user + $userId = $form->get('chill_reportbundle_report[user]')->getValue(); + + $this->assertEquals( + 'center a_social', + static::$user->getUsername(), + 'the user field is the current user by default' + ); + } + } } diff --git a/src/Bundle/ChillReportBundle/Tests/DependencyInjection/ChillReportExtensionTest.php b/src/Bundle/ChillReportBundle/Tests/DependencyInjection/ChillReportExtensionTest.php index beb246ea0..fd5bccde5 100644 --- a/src/Bundle/ChillReportBundle/Tests/DependencyInjection/ChillReportExtensionTest.php +++ b/src/Bundle/ChillReportBundle/Tests/DependencyInjection/ChillReportExtensionTest.php @@ -1,9 +1,20 @@ 'test')); + self::bootKernel(['environment' => 'test']); $customizablesEntities = static::$kernel->getContainer() - ->getParameter('chill_custom_fields.customizables_entities'); + ->getParameter('chill_custom_fields.customizables_entities'); $reportFounded = false; + foreach ($customizablesEntities as $customizablesEntity) { - if($customizablesEntity['class'] === 'Chill\ReportBundle\Entity\Report') { + if ('Chill\ReportBundle\Entity\Report' === $customizablesEntity['class']) { $reportFounded = true; } } - if(! $reportFounded) { - throw new Exception("Class Chill\ReportBundle\Entity\Report not found in chill_custom_fields.customizables_entities", 1); + if (!$reportFounded) { + throw new Exception('Class Chill\\ReportBundle\\Entity\\Report not found in chill_custom_fields.customizables_entities', 1); } } } diff --git a/src/Bundle/ChillReportBundle/Tests/Search/ReportSearchTest.php b/src/Bundle/ChillReportBundle/Tests/Search/ReportSearchTest.php index ce0bd1053..229a9d848 100644 --- a/src/Bundle/ChillReportBundle/Tests/Search/ReportSearchTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Search/ReportSearchTest.php @@ -1,126 +1,115 @@ - * - * 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 . +/** + * Chill is a software for social workers + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Tests\Search; +use DateTime; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test for report search + * Test for report search. * - * @author Julien Fastré + * @internal + * @coversNothing */ class ReportSearchTest extends WebTestCase { - - public function testSearchExpectedDefault() - { - $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@report 2015-01-05' - )); - - $this->assertTrue($client->getResponse()->isSuccessful()); - $this->assertRegExp('/Situation de logement/i', $crawler->text()); - } - public function testNamedSearch() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@report '.(new \DateTime('tomorrow'))->format('Y-m-d'), //there should be any result for future. And future is tomorrow - 'name' => 'report' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@report ' . (new DateTime('tomorrow'))->format('Y-m-d'), //there should be any result for future. And future is tomorrow + 'name' => 'report', + ]); + $this->assertTrue($client->getResponse()->isSuccessful()); } - + public function testSearchByDate() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@report date:2015-01-05' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@report date:2015-01-05', + ]); + $this->assertTrue($client->getResponse()->isSuccessful()); $this->assertRegExp('/Situation de logement/i', $crawler->text()); } - + public function testSearchDoubleDate() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@report date:2014-05-01 2014-05-06' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@report date:2014-05-01 2014-05-06', + ]); + $this->assertGreaterThan(0, $crawler->filter('.error')->count()); } - + public function testSearchEmtpy() { $client = $this->getAuthenticatedClient(); - - $crawler = $client->request('GET', '/fr/search', array( - 'q' => '@report ' - )); - + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@report ', + ]); + $this->assertGreaterThan(0, $crawler->filter('.error')->count()); } - + + public function testSearchExpectedDefault() + { + $client = $this->getAuthenticatedClient(); + + $crawler = $client->request('GET', '/fr/search', [ + 'q' => '@report 2015-01-05', + ]); + + $this->assertTrue($client->getResponse()->isSuccessful()); + $this->assertRegExp('/Situation de logement/i', $crawler->text()); + } + /** - * Test that the user do not see unauthorized results - * - * We test for that that : + * Test that the user do not see unauthorized results. + * + * We test for that that : * - we do not see any unauthorized scope mention */ public function testUsersDoNotSeeUnauthorizedResults() { $clientSocial = $this->getAuthenticatedClient(); $clientAdministrative = $this->getAuthenticatedClient('center a_administrative'); - - $params = array('q' => '@report date:2015-01-05'); - + + $params = ['q' => '@report date:2015-01-05']; + $crawlerSocial = $clientSocial->request('GET', '/fr/search', $params); $crawlerAdministrative = $clientAdministrative->request('GET', '/fr/search', $params); - - + $this->assertNotContains('social', $crawlerAdministrative->filter('.content') - ->text()); + ->text()); $this->assertNotContains('administrative', $crawlerAdministrative->filter('.content') - ->text()); + ->text()); } - - + /** - * + * @param mixed $username + * * @return \Symfony\Component\BrowserKit\Client */ private function getAuthenticatedClient($username = 'center a_social') { - return static::createClient(array(), array( - 'PHP_AUTH_USER' => $username, - 'PHP_AUTH_PW' => 'password', - )); + return static::createClient([], [ + 'PHP_AUTH_USER' => $username, + 'PHP_AUTH_PW' => 'password', + ]); } } diff --git a/src/Bundle/ChillReportBundle/Tests/Security/Authorization/ReportVoterTest.php b/src/Bundle/ChillReportBundle/Tests/Security/Authorization/ReportVoterTest.php index 8fa450fb0..f24f9e721 100644 --- a/src/Bundle/ChillReportBundle/Tests/Security/Authorization/ReportVoterTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Security/Authorization/ReportVoterTest.php @@ -1,122 +1,56 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Tests\Security\Authorization; -use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; -use Chill\MainBundle\Test\PrepareUserTrait; +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\User; use Chill\MainBundle\Test\PrepareCenterTrait; use Chill\MainBundle\Test\PrepareScopeTrait; -use Chill\ReportBundle\Entity\Report; -use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; -use Chill\MainBundle\Entity\User; -use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Test\PrepareUserTrait; use Chill\PersonBundle\Entity\Person; +use Chill\ReportBundle\Entity\Report; +use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; /** - * - * - * @author Julien Fastré + * @internal + * @coversNothing */ class ReportVoterTest extends KernelTestCase -{ - - use PrepareUserTrait, PrepareCenterTrait, PrepareScopeTrait; - +{ + use PrepareCenterTrait; + use PrepareScopeTrait; + use PrepareUserTrait; + /** - * - * @var \Chill\ReportBundle\Security\Authorization\ReportVoter - */ - protected $voter; - - /** - * * @var \Prophecy\Prophet */ protected $prophet; - + + /** + * @var \Chill\ReportBundle\Security\Authorization\ReportVoter + */ + protected $voter; + public static function setUpBeforeClass() { - } - + public function setUp() { static::bootKernel(); $this->voter = static::$kernel->getContainer() - ->get('chill.report.security.authorization.report_voter'); + ->get('chill.report.security.authorization.report_voter'); $this->prophet = new \Prophecy\Prophet(); } - - /** - * @dataProvider dataProvider - * @param type $expectedResult - * @param Report $report - * @param User $user - * @param type $action - * @param type $message - */ - public function testAccess($expectedResult, Report $report, $action, - $message, User $user = null) - { - $token = $this->prepareToken($user); - $result = $this->voter->vote($token, $report, [$action]); - $this->assertEquals($expectedResult, $result, $message); - } - - /** - * prepare a person - * - * The only properties set is the center, others properties are ignored. - * - * @param Center $center - * @return Person - */ - protected function preparePerson(Center $center) - { - return (new Person()) - ->setCenter($center) - ; - } - - /** - * prepare a token interface with correct rights - * - * if $permissions = null, user will be null (no user associated with token - * - * @param User $user - * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface - */ - protected function prepareToken(User $user = null) - { - $token = $this->prophet->prophesize(); - $token - ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - if ($user === NULL) { - $token->getUser()->willReturn(null); - } else { - $token->getUser()->willReturn($user); - } - - return $token->reveal(); - } - + public function dataProvider() { $centerA = $this->prepareCenter(1, 'center A'); @@ -124,70 +58,119 @@ class ReportVoterTest extends KernelTestCase $scopeA = $this->prepareScope(1, 'scope default'); $scopeB = $this->prepareScope(2, 'scope B'); $scopeC = $this->prepareScope(3, 'scope C'); - - $userA = $this->prepareUser(array( - array( - 'center' => $centerA, - 'permissionsGroup' => array( + + $userA = $this->prepareUser([ + [ + 'center' => $centerA, + 'permissionsGroup' => [ ['scope' => $scopeB, 'role' => 'CHILL_REPORT_SEE'], - ['scope' => $scopeA, 'role' => 'CHILL_REPORT_UPDATE'] - ) - ), - array( - 'center' => $centerB, - 'permissionsGroup' => array( - ['scope' => $scopeA, 'role' => 'CHILL_REPORT_SEE'], - ) - ) - - )); - - $reportA = (new Report) - ->setScope($scopeA) - ->setPerson($this->preparePerson($centerA)) - ; + ['scope' => $scopeA, 'role' => 'CHILL_REPORT_UPDATE'], + ], + ], + [ + 'center' => $centerB, + 'permissionsGroup' => [ + ['scope' => $scopeA, 'role' => 'CHILL_REPORT_SEE'], + ], + ], + ]); + + $reportA = (new Report()) + ->setScope($scopeA) + ->setPerson($this->preparePerson($centerA)); $reportB = (new Report()) - ->setScope($scopeB) - ->setPerson($this->preparePerson($centerA)) - ; + ->setScope($scopeB) + ->setPerson($this->preparePerson($centerA)); $reportC = (new Report()) - ->setScope($scopeC) - ->setPerson($this->preparePerson($centerB)) - ; - - - return array( - array( + ->setScope($scopeC) + ->setPerson($this->preparePerson($centerB)); + + return [ + [ VoterInterface::ACCESS_DENIED, $reportA, 'CHILL_REPORT_SEE', - "assert is denied to a null user", - null - ), - array( + 'assert is denied to a null user', + null, + ], + [ VoterInterface::ACCESS_GRANTED, $reportA, 'CHILL_REPORT_SEE', - "assert access is granted to a user with inheritance UPDATE > SEE", - $userA - ), - array( + 'assert access is granted to a user with inheritance UPDATE > SEE', + $userA, + ], + [ VoterInterface::ACCESS_GRANTED, $reportB, 'CHILL_REPORT_SEE', - "assert access is granted to a user without inheritance", - $userA - ), - array( + 'assert access is granted to a user without inheritance', + $userA, + ], + [ VoterInterface::ACCESS_DENIED, $reportC, 'CHILL_REPORT_SEE', 'assert access is denied to a report', - $userA - ) - ); - + $userA, + ], + ]; + } + + /** + * @dataProvider dataProvider + * + * @param type $expectedResult + * @param User $user + * @param type $action + * @param type $message + */ + public function testAccess( + $expectedResult, + Report $report, + $action, + $message, + ?User $user = null + ) { + $token = $this->prepareToken($user); + $result = $this->voter->vote($token, $report, [$action]); + $this->assertEquals($expectedResult, $result, $message); + } + + /** + * prepare a person. + * + * The only properties set is the center, others properties are ignored. + * + * @return Person + */ + protected function preparePerson(Center $center) + { + return (new Person()) + ->setCenter($center); + } + + /** + * prepare a token interface with correct rights. + * + * if $permissions = null, user will be null (no user associated with token + * + * @param User $user + * + * @return \Symfony\Component\Security\Core\Authentication\Token\TokenInterface + */ + protected function prepareToken(?User $user = null) + { + $token = $this->prophet->prophesize(); + $token + ->willImplement('\Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + if (null === $user) { + $token->getUser()->willReturn(null); + } else { + $token->getUser()->willReturn($user); + } + + return $token->reveal(); } - - } diff --git a/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php b/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php index 830600a6e..f49f42d3d 100644 --- a/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php +++ b/src/Bundle/ChillReportBundle/Tests/Timeline/TimelineProviderTest.php @@ -1,182 +1,88 @@ * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Tests\Timeline; -use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Chill\MainBundle\Entity\Scope; +use Chill\MainBundle\Tests\TestHelper as MainTestHelper; use Chill\PersonBundle\Entity\Person; use Chill\ReportBundle\Entity\Report; -use Chill\MainBundle\Tests\TestHelper as MainTestHelper; -use Chill\MainBundle\Entity\Scope; +use DateTime; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; /** - * Test a report is shown into timeline + * Test a report is shown into timeline. * - * @author Julien Fastré - * @author Champs Libres + * @internal + * @coversNothing */ class TimelineProviderTest extends WebTestCase { - /** - * * @var \Doctrine\ORM\EntityManager */ private static $em; - + /** - * * @var Person */ private $person; - + /** - * * @var Report */ private $report; - + /** - * Create a person with a report associated with the person + * Create a person with a report associated with the person. */ public function setUp() { static::bootKernel(); - + static::$em = static::$kernel->getContainer() - ->get('doctrine.orm.entity_manager'); - + ->get('doctrine.orm.entity_manager'); + $center = static::$em->getRepository('ChillMainBundle:Center') - ->findOneBy(array('name' => 'Center A')); - - $person = (new Person(new \DateTime('2015-05-01'))) - ->setGender(Person::FEMALE_GENDER) - ->setFirstName('Nelson') - ->setLastName('Mandela') - ->setCenter($center); + ->findOneBy(['name' => 'Center A']); + + $person = (new Person(new DateTime('2015-05-01'))) + ->setGender(Person::FEMALE_GENDER) + ->setFirstName('Nelson') + ->setLastName('Mandela') + ->setCenter($center); static::$em->persist($person); $this->person = $person; - - $scopesSocial = array_filter(static::$em + + $scopesSocial = array_filter( + static::$em ->getRepository('ChillMainBundle:Scope') - ->findAll(), - function(Scope $scope) { return $scope->getName()['en'] === 'social'; }) - ; - - $report = (new Report) - ->setUser(static::$em->getRepository('ChillMainBundle:User') - ->findOneByUsername('center a_social')) - ->setDate(new \DateTime('2015-05-02')) - ->setPerson($this->person) - ->setCFGroup($this->getHousingCustomFieldsGroup()) - ->setCFData(['has_logement' => 'own_house', - 'house-desc' => 'blah blah']) - ->setScope(end($scopesSocial)); - + ->findAll(), + function (Scope $scope) { return $scope->getName()['en'] === 'social'; } + ); + + $report = (new Report()) + ->setUser(static::$em->getRepository('ChillMainBundle:User') + ->findOneByUsername('center a_social')) + ->setDate(new DateTime('2015-05-02')) + ->setPerson($this->person) + ->setCFGroup($this->getHousingCustomFieldsGroup()) + ->setCFData(['has_logement' => 'own_house', + 'house-desc' => 'blah blah', ]) + ->setScope(end($scopesSocial)); + static::$em->persist($report); $this->report = $report; - - - - static::$em->flush(); - - } - - /** - * Test that a report is shown in timeline - */ - public function testTimelineReport() - { - $client = static::createClient(array(), - MainTestHelper::getAuthenticatedClientOptions() - ); - - $crawler = $client->request('GET', '/fr/person/'.$this->person->getId() - .'/timeline'); - - $this->assertTrue($client->getResponse()->isSuccessful(), - 'The page timeline is loaded successfully'); - $this->assertContains('a ajouté un rapport', $crawler->text(), - 'the page contains the text "a publié un rapport"'); - } - - public function testTimelineReportWithSummaryField() - { - //load the page - $client = static::createClient(array(), - MainTestHelper::getAuthenticatedClientOptions() - ); - - $crawler = $client->request('GET', '/fr/person/'.$this->person->getId() - .'/timeline'); - - //performs tests - $this->assertTrue($client->getResponse()->isSuccessful(), - 'The page timeline is loaded successfully'); - $this->assertGreaterThan(0, $crawler->filter('.report_entry .summary') - ->count(), - 'the page contains a .report .summary element'); - $this->assertContains('blah blah', $crawler->filter('.report_entry .summary') - ->text(), - 'the page contains the text "blah blah"'); - $this->assertContains('Propriétaire', $crawler->filter('.report_entry .summary') - ->text(), - 'the page contains the mention "Propriétaire"'); - } - - public function testReportIsNotVisibleToUngrantedUsers() - { - $client = static::createClient(array(), - MainTestHelper::getAuthenticatedClientOptions('center a_administrative') - ); - - $crawler = $client->request('GET', '/fr/person/'.$this->person->getId() - .'/timeline'); - $this->assertEquals(0, $crawler->filter('.report_entry .summary') - ->count(), - 'the page does not contains a .report .summary element'); + static::$em->flush(); } - - /** - * get a random custom fields group - * - * @return \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup - */ - private function getHousingCustomFieldsGroup() - { - $groups = static::$em - ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') - ->findAll(); - - foreach ($groups as $group) { - if ($group->getName()['fr'] === 'Situation de logement') { - return $group; - } - } - - return $groups[rand(0, count($groups) -1)]; - } - - - + public function tearDown() { //static::$em->refresh($this->person); @@ -184,4 +90,102 @@ class TimelineProviderTest extends WebTestCase // static::$em->remove($this->person); //static::$em->remove($this->report); } + + public function testReportIsNotVisibleToUngrantedUsers() + { + $client = static::createClient( + [], + MainTestHelper::getAuthenticatedClientOptions('center a_administrative') + ); + + $crawler = $client->request('GET', '/fr/person/' . $this->person->getId() + . '/timeline'); + + $this->assertEquals( + 0, + $crawler->filter('.report_entry .summary') + ->count(), + 'the page does not contains a .report .summary element' + ); + } + + /** + * Test that a report is shown in timeline. + */ + public function testTimelineReport() + { + $client = static::createClient( + [], + MainTestHelper::getAuthenticatedClientOptions() + ); + + $crawler = $client->request('GET', '/fr/person/' . $this->person->getId() + . '/timeline'); + + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page timeline is loaded successfully' + ); + $this->assertContains( + 'a ajouté un rapport', + $crawler->text(), + 'the page contains the text "a publié un rapport"' + ); + } + + public function testTimelineReportWithSummaryField() + { + //load the page + $client = static::createClient( + [], + MainTestHelper::getAuthenticatedClientOptions() + ); + + $crawler = $client->request('GET', '/fr/person/' . $this->person->getId() + . '/timeline'); + + //performs tests + $this->assertTrue( + $client->getResponse()->isSuccessful(), + 'The page timeline is loaded successfully' + ); + $this->assertGreaterThan( + 0, + $crawler->filter('.report_entry .summary') + ->count(), + 'the page contains a .report .summary element' + ); + $this->assertContains( + 'blah blah', + $crawler->filter('.report_entry .summary') + ->text(), + 'the page contains the text "blah blah"' + ); + $this->assertContains( + 'Propriétaire', + $crawler->filter('.report_entry .summary') + ->text(), + 'the page contains the mention "Propriétaire"' + ); + } + + /** + * get a random custom fields group. + * + * @return \Chill\CustomFieldsBundle\Entity\CustomFieldsGroup + */ + private function getHousingCustomFieldsGroup() + { + $groups = static::$em + ->getRepository('ChillCustomFieldsBundle:CustomFieldsGroup') + ->findAll(); + + foreach ($groups as $group) { + if ($group->getName()['fr'] === 'Situation de logement') { + return $group; + } + } + + return $groups[rand(0, count($groups) - 1)]; + } } diff --git a/src/Bundle/ChillReportBundle/Tests/bootstrap.php b/src/Bundle/ChillReportBundle/Tests/bootstrap.php index 2437ecd2d..0eb126c4f 100644 --- a/src/Bundle/ChillReportBundle/Tests/bootstrap.php +++ b/src/Bundle/ChillReportBundle/Tests/bootstrap.php @@ -1,7 +1,14 @@ * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ReportBundle\Timeline; -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManager; +use Chill\CustomFieldsBundle\Service\CustomFieldsHelper; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Timeline\TimelineProviderInterface; +use Chill\PersonBundle\Entity\Person; +use Chill\ReportBundle\Entity\Report; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\ClassMetadata; +use LogicException; +use RuntimeException; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Role\Role; -use Doctrine\ORM\Mapping\ClassMetadata; -use Chill\PersonBundle\Entity\Person; -use Chill\MainBundle\Entity\Scope; -use Chill\CustomFieldsBundle\Service\CustomFieldsHelper; -use Chill\ReportBundle\Entity\Report; /** - * Provide report for inclusion in timeline - * - * @author Julien Fastré - * @author Champs Libres + * Provide report for inclusion in timeline. */ class TimelineReportProvider implements TimelineProviderInterface { - /** - * - * @var EntityManager - */ - protected $em; - - /** - * - * @var AuthorizationHelper - */ - protected $helper; - - /** - * - * @var \Chill\MainBundle\Entity\User - */ - protected $user; - - /** - * * @var CustomFieldsHelper */ protected $customFieldsHelper; - + + /** + * @var EntityManager + */ + protected $em; + + /** + * @var AuthorizationHelper + */ + protected $helper; + /** * @var */ protected $showEmptyValues; - + + /** + * @var \Chill\MainBundle\Entity\User + */ + protected $user; + /** * TimelineReportProvider constructor. * - * @param EntityManager $em - * @param AuthorizationHelper $helper - * @param TokenStorageInterface $storage - * @param CustomFieldsHelper $customFieldsHelper * @param $showEmptyValues */ public function __construct( @@ -84,164 +63,123 @@ class TimelineReportProvider implements TimelineProviderInterface TokenStorageInterface $storage, CustomFieldsHelper $customFieldsHelper, $showEmptyValues - ) - { + ) { $this->em = $em; $this->helper = $helper; - - if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) - { - throw new \RuntimeException('A user should be authenticated !'); + + if (!$storage->getToken()->getUser() instanceof \Chill\MainBundle\Entity\User) { + throw new RuntimeException('A user should be authenticated !'); } - + $this->user = $storage->getToken()->getUser(); $this->customFieldsHelper = $customFieldsHelper; $this->showEmptyValues = $showEmptyValues; } - - /** - * - * {@inheritDoc} - */ + public function fetchQuery($context, array $args) { $this->checkContext($context); - + $metadataReport = $this->em->getClassMetadata('ChillReportBundle:Report'); $metadataPerson = $this->em->getClassMetadata('ChillPersonBundle:Person'); - - return array( - 'id' => $metadataReport->getTableName() - .'.'.$metadataReport->getColumnName('id'), - 'type' => 'report', - 'date' => $metadataReport->getTableName() - .'.'.$metadataReport->getColumnName('date'), - 'FROM' => $this->getFromClause($metadataReport, $metadataPerson), - 'WHERE' => $this->getWhereClause($metadataReport, $metadataPerson, - $args['person']) - ); - } - - private function getWhereClause(ClassMetadata $metadataReport, - ClassMetadata $metadataPerson, Person $person) - { - $role = new Role('CHILL_REPORT_SEE'); - $reachableCenters = $this->helper->getReachableCenters($this->user, - $role); - $associationMapping = $metadataReport->getAssociationMapping('person'); - - // we start with reports having the person_id linked to person - // (currently only context "person" is supported) - $whereClause = sprintf('%s = %d', - $associationMapping['joinColumns'][0]['name'], - $person->getId()); - - // we add acl (reachable center and scopes) - $centerAndScopeLines = array(); - foreach ($reachableCenters as $center) { - $reachablesScopesId = array_map( - function(Scope $scope) { return $scope->getId(); }, - $this->helper->getReachableScopes($this->user, $role, - $person->getCenter()) - ); - - $centerAndScopeLines[] = sprintf('(%s = %d AND %s IN (%s))', - $metadataPerson->getTableName().'.'. - $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], - $center->getId(), - $metadataReport->getTableName().'.'. - $metadataReport->getAssociationMapping('scope')['joinColumns'][0]['name'], - implode(',', $reachablesScopesId)); - - } - $whereClause .= ' AND ('.implode(' OR ', $centerAndScopeLines).')'; - - return $whereClause; - } - - private function getFromClause(ClassMetadata $metadataReport, - ClassMetadata $metadataPerson) - { - $associationMapping = $metadataReport->getAssociationMapping('person'); - - return $metadataReport->getTableName().' JOIN ' - .$metadataPerson->getTableName().' ON ' - .$metadataPerson->getTableName().'.'. - $associationMapping['joinColumns'][0]['referencedColumnName'] - .' = ' - .$associationMapping['joinColumns'][0]['name'] - ; + + return [ + 'id' => $metadataReport->getTableName() + . '.' . $metadataReport->getColumnName('id'), + 'type' => 'report', + 'date' => $metadataReport->getTableName() + . '.' . $metadataReport->getColumnName('date'), + 'FROM' => $this->getFromClause($metadataReport, $metadataPerson), + 'WHERE' => $this->getWhereClause( + $metadataReport, + $metadataPerson, + $args['person'] + ), + ]; } - /** - * - * {@inheritDoc} - */ public function getEntities(array $ids) { $reports = $this->em->getRepository('ChillReportBundle:Report') - ->findBy(array('id' => $ids)); - - $result = array(); - foreach($reports as $report) { + ->findBy(['id' => $ids]); + + $result = []; + + foreach ($reports as $report) { $result[$report->getId()] = $report; } - + return $result; } - /** - * - * {@inheritDoc} - */ public function getEntityTemplate($entity, $context, array $args) { $this->checkContext($context); - - return array( - 'template' => 'ChillReportBundle:Timeline:report_person_context.html.twig', - 'template_data' => array( - 'report' => $entity, - 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context), - 'person' => $args['person'], - 'user' => $entity->getUser() - ) - ); + + return [ + 'template' => 'ChillReportBundle:Timeline:report_person_context.html.twig', + 'template_data' => [ + 'report' => $entity, + 'custom_fields_in_summary' => $this->getFieldsToRender($entity, $context), + 'person' => $args['person'], + 'user' => $entity->getUser(), + ], + ]; } - - protected function getFieldsToRender(Report $entity, $context, array $args = array()) + + public function supportsType($type) + { + return 'report' === $type; + } + + protected function getFieldsToRender(Report $entity, $context, array $args = []) { //gather all custom fields which should appears in summary - $gatheredFields = array(); - + $gatheredFields = []; + if (array_key_exists('summary_fields', $entity->getCFGroup()->getOptions())) { // keep in memory title $title = null; $subtitle = null; - + foreach ($entity->getCFGroup()->getCustomFields() as $customField) { - if (in_array($customField->getSlug(), - $entity->getCFGroup()->getOptions()['summary_fields'])) { + if ( + in_array( + $customField->getSlug(), + $entity->getCFGroup()->getOptions()['summary_fields'] + ) + ) { // if we do not want to show empty values - if ($this->showEmptyValues === false) { + if (false === $this->showEmptyValues) { if ($customField->getType() === 'title') { $options = $customField->getOptions(); - switch($options['type']) { - case 'title': $title = $customField; break; - case 'subtitle': $subtitle = $customField; break; + + switch ($options['type']) { + case 'title': + $title = $customField; + + break; + + case 'subtitle': + $subtitle = $customField; + + break; } } else { - if ($this->customFieldsHelper->isEmptyValue($entity->getCFData(), $customField) - === false) { - if ($title !== NULL) { + if ( + $this->customFieldsHelper->isEmptyValue($entity->getCFData(), $customField) + === false + ) { + if (null !== $title) { $gatheredFields[] = $title; $title = null; } - if ($subtitle !== NULL) { + + if (null !== $subtitle) { $gatheredFields[] = $subtitle; $subtitle = null; } - $gatheredFields[] = $customField; + $gatheredFields[] = $customField; } } } else { @@ -250,32 +188,86 @@ class TimelineReportProvider implements TimelineProviderInterface } } } - + return $gatheredFields; - } /** - * - * {@inheritDoc} - */ - public function supportsType($type) - { - return $type === 'report'; - } - - /** - * check if the context is supported - * + * check if the context is supported. + * * @param string $context - * @throws \LogicException if the context is not supported + * + * @throws LogicException if the context is not supported */ private function checkContext($context) { - if ($context !== 'person') { - throw new \LogicException("The context '$context' is not " + if ('person' !== $context) { + throw new LogicException("The context '{$context}' is not " . "supported. Currently only 'person' is supported"); } } + private function getFromClause( + ClassMetadata $metadataReport, + ClassMetadata $metadataPerson + ) { + $associationMapping = $metadataReport->getAssociationMapping('person'); + + return $metadataReport->getTableName() . ' JOIN ' + . $metadataPerson->getTableName() . ' ON ' + . $metadataPerson->getTableName() . '.' . + $associationMapping['joinColumns'][0]['referencedColumnName'] + . ' = ' + . $associationMapping['joinColumns'][0]['name']; + } + + private function getWhereClause( + ClassMetadata $metadataReport, + ClassMetadata $metadataPerson, + Person $person + ) { + $role = new Role('CHILL_REPORT_SEE'); + $reachableCenters = $this->helper->getReachableCenters( + $this->user, + $role + ); + $associationMapping = $metadataReport->getAssociationMapping('person'); + + // we start with reports having the person_id linked to person + // (currently only context "person" is supported) + $whereClause = sprintf( + '%s = %d', + $associationMapping['joinColumns'][0]['name'], + $person->getId() + ); + + // we add acl (reachable center and scopes) + $centerAndScopeLines = []; + + foreach ($reachableCenters as $center) { + $reachablesScopesId = array_map( + function (Scope $scope) { + return $scope->getId(); + }, + $this->helper->getReachableScopes( + $this->user, + $role, + $person->getCenter() + ) + ); + + $centerAndScopeLines[] = sprintf( + '(%s = %d AND %s IN (%s))', + $metadataPerson->getTableName() . '.' . + $metadataPerson->getAssociationMapping('center')['joinColumns'][0]['name'], + $center->getId(), + $metadataReport->getTableName() . '.' . + $metadataReport->getAssociationMapping('scope')['joinColumns'][0]['name'], + implode(',', $reachablesScopesId) + ); + } + $whereClause .= ' AND (' . implode(' OR ', $centerAndScopeLines) . ')'; + + return $whereClause; + } } diff --git a/src/Bundle/ChillReportBundle/migrations/Version20141129012050.php b/src/Bundle/ChillReportBundle/migrations/Version20141129012050.php index 3108024f8..57d64f9b6 100644 --- a/src/Bundle/ChillReportBundle/migrations/Version20141129012050.php +++ b/src/Bundle/ChillReportBundle/migrations/Version20141129012050.php @@ -1,30 +1,36 @@ addSql("CREATE SEQUENCE Report_id_seq INCREMENT BY 1 MINVALUE 1 START 1;"); - $this->addSql("CREATE TABLE Report (id INT NOT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, scope VARCHAR(255) DEFAULT NULL, cFData JSON NOT NULL, cFGroup_id INT DEFAULT NULL, PRIMARY KEY(id));"); - $this->addSql("CREATE INDEX IDX_C38372B2A76ED395 ON Report (user_id);"); - $this->addSql("CREATE INDEX IDX_C38372B2217BBB47 ON Report (person_id);"); - $this->addSql("CREATE INDEX IDX_C38372B216D2C9F0 ON Report (cFGroup_id);"); - $this->addSql("ALTER TABLE Report ADD CONSTRAINT FK_C38372B2A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE Report ADD CONSTRAINT FK_C38372B2217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - $this->addSql("ALTER TABLE Report ADD CONSTRAINT FK_C38372B216D2C9F0 FOREIGN KEY (cFGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;"); - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs + } + public function up(Schema $schema): void + { + $this->addSql('CREATE SEQUENCE Report_id_seq INCREMENT BY 1 MINVALUE 1 START 1;'); + $this->addSql('CREATE TABLE Report (id INT NOT NULL, user_id INT DEFAULT NULL, person_id INT DEFAULT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, scope VARCHAR(255) DEFAULT NULL, cFData JSON NOT NULL, cFGroup_id INT DEFAULT NULL, PRIMARY KEY(id));'); + $this->addSql('CREATE INDEX IDX_C38372B2A76ED395 ON Report (user_id);'); + $this->addSql('CREATE INDEX IDX_C38372B2217BBB47 ON Report (person_id);'); + $this->addSql('CREATE INDEX IDX_C38372B216D2C9F0 ON Report (cFGroup_id);'); + $this->addSql('ALTER TABLE Report ADD CONSTRAINT FK_C38372B2A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE Report ADD CONSTRAINT FK_C38372B2217BBB47 FOREIGN KEY (person_id) REFERENCES Person (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); + $this->addSql('ALTER TABLE Report ADD CONSTRAINT FK_C38372B216D2C9F0 FOREIGN KEY (cFGroup_id) REFERENCES CustomFieldsGroup (id) NOT DEFERRABLE INITIALLY IMMEDIATE;'); } } diff --git a/src/Bundle/ChillReportBundle/migrations/Version20150622233319.php b/src/Bundle/ChillReportBundle/migrations/Version20150622233319.php index 3e0353b41..6a45e09ce 100644 --- a/src/Bundle/ChillReportBundle/migrations/Version20150622233319.php +++ b/src/Bundle/ChillReportBundle/migrations/Version20150622233319.php @@ -1,62 +1,78 @@ abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); + + $this->addSql('ALTER TABLE Report DROP CONSTRAINT FK_report_scope'); + $this->addSql('DROP INDEX IDX_report_scope'); + $this->addSql('ALTER TABLE Report ADD scope VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE Report DROP scope_id'); + } + + public function setContainer(?ContainerInterface $container = null) + { + if (null === $container) { + throw new RuntimeException('Container is not provided. This migration ' . 'need container to set a default center'); } - + $this->container = $container; } - - /** - * @param Schema $schema - */ + public function up(Schema $schema): void { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); + $this->abortIf( + $this->connection->getDatabasePlatform()->getName() != 'postgresql', + 'Migration can only be executed safely on \'postgresql\'.' + ); $this->addSql('ALTER TABLE report ADD scope_id INT DEFAULT NULL'); - + /* * Before the upgrade to symfony version 4, this code worked. - * + * * But it doesn't work any more after the migration and currently this * code should note be necessary. - * + * * This code is kept for reference, and may be re-activated if needed, but * the probability that this will happens is near 0 - * + * //add a default scope $scopes = $this->container->get('doctrine.orm.default_entity_manager') ->getRepository('ChillMainBundle:Scope') ->findAll(); - + if (count($scopes) > 0) { $defaultScopeId = $scopes[0]->getId(); } else { @@ -64,7 +80,7 @@ class Version20150622233319 extends AbstractMigration $nbReports = $this->container->get('doctrine.orm.default_entity_manager') ->createQuery('SELECT count(r.id) FROM ChillReportBundle:Report r') ->getSingleScalarResult(); - + if ($nbReports > 0) { //create a default scope $scope = new Scope(); @@ -90,27 +106,13 @@ class Version20150622233319 extends AbstractMigration $this->addSql('ALTER TABLE report ADD CONSTRAINT FK_report_scope ' . 'FOREIGN KEY (scope_id) ' . 'REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - if (isset($defaultScopeId)){ - $this->addSql('UPDATE report SET scope_id = :id', array( - 'id' => $defaultScopeId - )); + + if (isset($defaultScopeId)) { + $this->addSql('UPDATE report SET scope_id = :id', [ + 'id' => $defaultScopeId, + ]); } $this->addSql('ALTER TABLE report ALTER COLUMN scope_id SET NOT NULL'); $this->addSql('CREATE INDEX IDX_report_scope ON report (scope_id)'); } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', - 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE Report DROP CONSTRAINT FK_report_scope'); - $this->addSql('DROP INDEX IDX_report_scope'); - $this->addSql('ALTER TABLE Report ADD scope VARCHAR(255) DEFAULT NULL'); - $this->addSql('ALTER TABLE Report DROP scope_id'); - } } diff --git a/src/Bundle/ChillTaskBundle/ChillTaskBundle.php b/src/Bundle/ChillTaskBundle/ChillTaskBundle.php index acd8b8607..cd3b1fdf7 100644 --- a/src/Bundle/ChillTaskBundle/ChillTaskBundle.php +++ b/src/Bundle/ChillTaskBundle/ChillTaskBundle.php @@ -1,36 +1,24 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle; - -use Symfony\Component\HttpKernel\Bundle\Bundle; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Chill\TaskBundle\DependencyInjection\Compiler\TaskWorkflowDefinitionCompilerPass; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle; + +use Chill\TaskBundle\DependencyInjection\Compiler\TaskWorkflowDefinitionCompilerPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; + class ChillTaskBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); - + $container->addCompilerPass(new TaskWorkflowDefinitionCompilerPass()); } } diff --git a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php index 1c526aa1e..1f3085e0d 100644 --- a/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/SingleTaskController.php @@ -1,63 +1,66 @@ timelineBuilder = $timelineBuilder; $this->logger = $logger; } - - + /** * @Route( - * "/{_locale}/task/single-task/new", - * name="chill_task_single_task_new" + * "/{_locale}/task/single-task/{id}/delete", + * name="chill_task_single_task_delete" * ) + * + * @param mixed $id */ - public function newAction( + public function deleteAction( Request $request, + $id, TranslatorInterface $translator ) { - - $task = (new SingleTask()) - ->setAssignee($this->getUser()) - ->setType('task_default') - ; - - if ($request->query->has('person_id')) { - - $personId = $request->query->getInt('person_id', 0); // sf4 check: - // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` - - if ($personId === null) { - return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); - } - - $person = $this->getDoctrine()->getManager() - ->getRepository(Person::class) - ->find($personId); - - if ($person === null) { - $this->createNotFoundException("Invalid person id"); - } - - $task->setPerson($person); - } - - $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' - . 'allowed to create this task'); - - $form = $this->setCreateForm($task, new Role(TaskVoter::CREATE)); - - $form->handleRequest($request); - - if ($form->isSubmitted()) { - if ($form->isValid()) { - $em = $this->getDoctrine()->getManager(); - $em->persist($task); - - $this->eventDispatcher->dispatch(TaskEvent::PERSIST, new TaskEvent($task)); - - $em->flush(); - - $this->addFlash('success', $translator->trans("The task is created")); - - return $this->redirectToRoute('chill_task_singletask_list', [ - 'person_id' => $task->getPerson()->getId() - ]); - - } else { - $this->addFlash('error', $translator->trans("This form contains errors")); - } - } - - return $this->render('ChillTaskBundle:SingleTask:new.html.twig', array( - 'form' => $form->createView(), - 'task' => $task - )); - } - - - /** - * @Route( - * "/{_locale}/task/single-task/{id}/show", - * name="chill_task_single_task_show" - * ) - */ - public function showAction(Request $request, $id) - { - $em = $this->getDoctrine()->getManager(); $task = $em->getRepository(SingleTask::class)->find($id); - if ($task->getPerson() !== null) { - $personId = $task->getPerson()->getId(); - - if ($personId === null) { - return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); - } - - $person = $this->getDoctrine()->getManager() - ->getRepository(Person::class) - ->find($personId); - - if ($person === null) { - throw $this->createNotFoundException("Invalid person id"); - } - } - $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task, 'You are not ' - . 'allowed to view this task'); - if (!$task) { throw $this->createNotFoundException('Unable to find Task entity.'); } - $timeline = $this->timelineBuilder - ->getTimelineHTML('task', array('task' => $task)); - - $event = new PrivacyEvent($person, array( - 'element_class' => SingleTask::class, - 'element_id' => $task->getId(), - 'action' => 'show' - )); - $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array( - 'task' => $task, - 'timeline' => $timeline - )); - } + if ($task->getPerson() !== null) { + $personId = $task->getPerson()->getId(); + if (null === $personId) { + return new Response('You must provide a person_id', Response::HTTP_BAD_REQUEST); + } + + $person = $this->getDoctrine()->getManager() + ->getRepository(Person::class) + ->find($personId); + + if (null === $person) { + throw $this->createNotFoundException('Invalid person id'); + } + } + + $this->denyAccessUnlessGranted(TaskVoter::DELETE, $task, 'You are not ' + . 'allowed to delete this task'); + + $form = $this->createDeleteForm($id); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $this->logger->notice('A task has been removed', [ + 'by_user' => $this->getUser()->getUsername(), + 'task_id' => $task->getId(), + 'description' => $task->getDescription(), + 'assignee' => $task->getAssignee(), + 'scope_id' => $task->getScope()->getId(), + //'start_date' => $task->getStartDate()->format('Y-m-d'), + //'end_date' => $task->getEndDate()->format('Y-m-d'), + //'warning_interval' => $task->getWarningInterval()->format('Y-m-d') + ]); + + $em = $this->getDoctrine()->getManager(); + $em->remove($task); + $em->flush(); + + $this->addFlash('success', $translator + ->trans('The task has been successfully removed.')); + + return $this->redirect($this->generateUrl( + 'chill_task_singletask_list', + $request->query->get('list_params', [ + 'person_id' => $person->getId(), + ]) + )); + } + } + + return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', [ + 'task' => $task, + 'delete_form' => $form->createView(), + ]); + } /** * @Route( - * "/{_locale}/task/single-task/{id}/edit", - * name="chill_task_single_task_edit" + * "/{_locale}/task/single-task/{id}/edit", + * name="chill_task_single_task_edit" * ) + * + * @param mixed $id */ public function editAction( Request $request, $id, TranslatorInterface $translator ) { - $em = $this->getDoctrine()->getManager(); $task = $em->getRepository(SingleTask::class)->find($id); if ($task->getPerson() !== null) { $personId = $task->getPerson()->getId(); - if ($personId === null) { - return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); + + if (null === $personId) { + return new Response('You must provide a person_id', Response::HTTP_BAD_REQUEST); } $person = $this->getDoctrine()->getManager() ->getRepository(Person::class) ->find($personId); - if ($person === null) { - throw $this->createNotFoundException("Invalid person id"); + if (null === $person) { + throw $this->createNotFoundException('Invalid person id'); } } $this->denyAccessUnlessGranted(TaskVoter::UPDATE, $task, 'You are not ' @@ -226,13 +187,12 @@ class SingleTaskController extends AbstractController if (!$task) { throw $this->createNotFoundException('Unable to find Task entity.'); } - + $event = (new UIEvent('single-task', $task)) - ->setForm($this->setCreateForm($task, new Role(TaskVoter::UPDATE))) - ; - + ->setForm($this->setCreateForm($task, new Role(TaskVoter::UPDATE))); + $this->eventDispatcher->dispatch(UIEvent::EDIT_FORM, $event); - + $form = $event->getForm(); $form->handleRequest($request); @@ -245,170 +205,53 @@ class SingleTaskController extends AbstractController $em->flush(); $this->addFlash('success', $translator - ->trans("The task has been updated")); - - $event = new PrivacyEvent($person, array( + ->trans('The task has been updated')); + + $event = new PrivacyEvent($person, [ 'element_class' => SingleTask::class, 'element_id' => $task->getId(), - 'action' => 'update' - )); + 'action' => 'update', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); return $this->redirectToRoute( - 'chill_task_singletask_list', + 'chill_task_singletask_list', $request->query->get('list_params', []) ); - - } else { - $this->addFlash('error', $translator->trans("This form contains errors")); } + $this->addFlash('error', $translator->trans('This form contains errors')); } - + $this->eventDispatcher->dispatch(UIEvent::EDIT_PAGE, $event); - + if ($event->hasResponse()) { return $event->getResponse(); } - - $event = new PrivacyEvent($person, array( + + $event = new PrivacyEvent($person, [ 'element_class' => SingleTask::class, 'element_id' => $task->getId(), - 'action' => 'edit' - )); + 'action' => 'edit', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); - - return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', array( - 'task' => $task, - 'form' => $form->createView() - )); - } - - /** - * @Route( - * "/{_locale}/task/single-task/{id}/delete", - * name="chill_task_single_task_delete" - * ) - */ - public function deleteAction( - Request $request, - $id, - TranslatorInterface $translator - ) { - - $em = $this->getDoctrine()->getManager(); - $task = $em->getRepository(SingleTask::class)->find($id); - - if (!$task) { - throw $this->createNotFoundException('Unable to find Task entity.'); - } - - if ($task->getPerson() !== null) { - $personId = $task->getPerson()->getId(); - if ($personId === null) { - return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST); - } - - $person = $this->getDoctrine()->getManager() - ->getRepository(Person::class) - ->find($personId); - - if ($person === null) { - throw $this->createNotFoundException("Invalid person id"); - } - - } - - $this->denyAccessUnlessGranted(TaskVoter::DELETE, $task, 'You are not ' - . 'allowed to delete this task'); - - $form = $this->createDeleteForm($id); - - if ($request->getMethod() === Request::METHOD_DELETE) { - $form->handleRequest($request); - - if ($form->isValid()) { - - $this->logger->notice("A task has been removed", array( - 'by_user' => $this->getUser()->getUsername(), - 'task_id' => $task->getId(), - 'description' => $task->getDescription(), - 'assignee' => $task->getAssignee(), - 'scope_id' => $task->getScope()->getId(), - //'start_date' => $task->getStartDate()->format('Y-m-d'), - //'end_date' => $task->getEndDate()->format('Y-m-d'), - //'warning_interval' => $task->getWarningInterval()->format('Y-m-d') - )); - - $em = $this->getDoctrine()->getManager(); - $em->remove($task); - $em->flush(); - - $this->addFlash('success', $translator - ->trans("The task has been successfully removed.")); - - return $this->redirect($this->generateUrl( - 'chill_task_singletask_list', - $request->query->get('list_params', [ - 'person_id' => $person->getId() - ]))); - } - } - - - return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', array( - 'task' => $task, - 'delete_form' => $form->createView() - )); - } - - /** - * - * @param SingleTask $task - * @param Role $role - * @return \Symfony\Component\Form\FormInterface - */ - protected function setCreateForm(SingleTask $task, Role $role) - { - $form = $this->createForm(SingleTaskType::class, $task, [ - 'center' => $task->getCenter(), - 'role' => $role - ]); - - $form->add('submit', SubmitType::class); - - return $form; - } - - /** - * - * @return Response - * @Route( - * "/{_locale}/task/single-task/list/my", - * name="chill_task_single_my_tasks" - * ) - */ - public function myTasksAction(TranslatorInterface $translator) - { - return $this->redirectToRoute('chill_task_singletask_list', [ - 'user_id' => $this->getUser()->getId(), - 'hide_form' => true, - 'title' => $translator->trans('My tasks') + return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', [ + 'task' => $task, + 'form' => $form->createView(), ]); } /** - * * Arguments: * - user_id * - scope_id * - person_id * - hide_form (hide the form to filter the tasks) - * - status: date state, amongst SingleTaskRepository::DATE_STATUSES, or 'closed' + * - status: date state, amongst SingleTaskRepository::DATE_STATUSES, or 'closed'. * * @Route( - * "/{_locale}/task/singletask/list", - * name="chill_task_singletask_list" + * "/{_locale}/task/singletask/list", + * name="chill_task_singletask_list" * ) */ public function listAction( @@ -429,49 +272,48 @@ class SingleTaskController extends AbstractController $viewParams['center'] = null; $params['types'] = null; - // Get parameters from url - if (!empty($request->query->get('person_id', NULL))) { - + if (!empty($request->query->get('person_id', null))) { $personId = $request->query->getInt('person_id', 0); $person = $personRepository->find($personId); - if ($person === null) { - throw $this->createNotFoundException("This person ' $personId ' does not exist."); + if (null === $person) { + throw $this->createNotFoundException("This person ' {$personId} ' does not exist."); } $this->denyAccessUnlessGranted(PersonVoter::SEE, $person); $viewParams['person'] = $person; $params['person'] = $person; } - - if (!empty($request->query->get('center_id', NULL))) { + + if (!empty($request->query->get('center_id', null))) { $center = $centerRepository->find($request->query->getInt('center_id')); - if ($center === null) { + + if (null === $center) { throw $this->createNotFoundException('center not found'); } $params['center'] = $center; } - - if(!empty($request->query->get('types', []))) { + + if (!empty($request->query->get('types', []))) { $types = $request->query->get('types', []); + if (count($types) > 0) { $params['types'] = $types; } } - + if (!empty($request->query->get('user_id', null))) { if ($request->query->get('user_id') === '_unassigned') { $params['unassigned'] = true; } else { - $userId = $request->query->getInt('user_id', 0); $user = $this->getDoctrine()->getManager() ->getRepository('ChillMainBundle:User') ->find($userId); - if ($user === null) { - throw $this->createNotFoundException("This user ' $userId ' does not exist."); + if (null === $user) { + throw $this->createNotFoundException("This user ' {$userId} ' does not exist."); } $viewParams['user'] = $user; @@ -480,15 +322,14 @@ class SingleTaskController extends AbstractController } if (!empty($request->query->get('scope_id'))) { - $scopeId = $request->query->getInt('scope_id', 0); - + $scope = $this->getDoctrine()->getManager() ->getRepository('ChillMainBundle:Scope') ->find($scopeId); - if ($scope === null) { - throw $this->createNotFoundException("This scope' $scopeId 'does not exist."); + if (null === $scope) { + throw $this->createNotFoundException("This scope' {$scopeId} 'does not exist."); } $viewParams['scope'] = $scope; @@ -496,49 +337,53 @@ class SingleTaskController extends AbstractController } // collect parameters for filter - $possibleStatuses = \array_merge(SingleTaskRepository::DATE_STATUSES, [ 'closed' ]); + $possibleStatuses = array_merge(SingleTaskRepository::DATE_STATUSES, ['closed']); $statuses = $request->query->get('status', $possibleStatuses); // check for invalid statuses - $diff = \array_diff($statuses, $possibleStatuses); + $diff = array_diff($statuses, $possibleStatuses); + if (count($diff) > 0) { return new Response( - 'date_status not allowed: '. \implode(', ', $diff), - Response::HTTP_BAD_REQUEST - ); + 'date_status not allowed: ' . implode(', ', $diff), + Response::HTTP_BAD_REQUEST + ); } $viewParams['isSingleStatus'] = $singleStatus = count($statuses) === 1; $tasks_count = 0; - foreach($statuses as $status) { - if($request->query->has('status') - && FALSE === \in_array($status, $statuses)) { + foreach ($statuses as $status) { + if ( + $request->query->has('status') + && false === \in_array($status, $statuses) + ) { continue; } // different query if regarding to date or 'closed' if (in_array($status, SingleTaskRepository::DATE_STATUSES)) { $params['date_status'] = $status; - $params['is_closed'] = false; + $params['is_closed'] = false; } else { $params['date_status'] = null; - $params['is_closed'] = true; + $params['is_closed'] = true; } $count = $taskRepository - ->countByParameters($params, $this->getUser()) - ; + ->countByParameters($params, $this->getUser()); $paginator = $paginatorFactory->create($count); - $viewParams['single_task_'.$status.'_count'] = $count; - $viewParams['single_task_'.$status.'_paginator'] = $paginator; - $viewParams['single_task_'.$status.'_tasks'] = $taskRepository - ->findByParameters($params, $this->getUser(), + $viewParams['single_task_' . $status . '_count'] = $count; + $viewParams['single_task_' . $status . '_paginator'] = $paginator; + $viewParams['single_task_' . $status . '_tasks'] = $taskRepository + ->findByParameters( + $params, + $this->getUser(), $singleStatus ? $paginator->getCurrentPage()->getFirstItemNumber() : 0, - $singleStatus ? $paginator->getItemsPerPage() : 10) - ; + $singleStatus ? $paginator->getItemsPerPage() : 10 + ); $tasks_count = $tasks_count + $count; } @@ -546,7 +391,7 @@ class SingleTaskController extends AbstractController // total number of tasks $viewParams['tasks_count'] = $tasks_count; - if ($viewParams['person'] !== null){ + if (null !== $viewParams['person']) { $viewParams['layout'] = 'ChillPersonBundle::layout.html.twig'; } else { $viewParams['layout'] = '@ChillMain/layout.html.twig'; @@ -557,36 +402,167 @@ class SingleTaskController extends AbstractController 'person' => $viewParams['person'], 'method' => Request::METHOD_GET, 'csrf_protection' => false, - 'add_type' => true + 'add_type' => true, ]); $form->handleRequest($request); - + if (isset($person)) { - $event = new PrivacyEvent($person, array( + $event = new PrivacyEvent($person, [ 'element_class' => SingleTask::class, - 'action' => 'list' - )); + 'action' => 'list', + ]); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); } - - return $this->render('ChillTaskBundle:SingleTask:index.html.twig', - \array_merge($viewParams, [ 'form' => $form->createView() ])); + + return $this->render( + 'ChillTaskBundle:SingleTask:index.html.twig', + array_merge($viewParams, ['form' => $form->createView()]) + ); } + /** + * @return Response + * @Route( + * "/{_locale}/task/single-task/list/my", + * name="chill_task_single_my_tasks" + * ) + */ + public function myTasksAction(TranslatorInterface $translator) + { + return $this->redirectToRoute('chill_task_singletask_list', [ + 'user_id' => $this->getUser()->getId(), + 'hide_form' => true, + 'title' => $translator->trans('My tasks'), + ]); + } + + /** + * @Route( + * "/{_locale}/task/single-task/new", + * name="chill_task_single_task_new" + * ) + */ + public function newAction( + Request $request, + TranslatorInterface $translator + ) { + $task = (new SingleTask()) + ->setAssignee($this->getUser()) + ->setType('task_default'); + + if ($request->query->has('person_id')) { + $personId = $request->query->getInt('person_id', 0); // sf4 check: + // prevent error: `Argument 2 passed to ::getInt() must be of the type int, null given` + + if (null === $personId) { + return new Response('You must provide a person_id', Response::HTTP_BAD_REQUEST); + } + + $person = $this->getDoctrine()->getManager() + ->getRepository(Person::class) + ->find($personId); + + if (null === $person) { + $this->createNotFoundException('Invalid person id'); + } + + $task->setPerson($person); + } + + $this->denyAccessUnlessGranted(TaskVoter::CREATE, $task, 'You are not ' + . 'allowed to create this task'); + + $form = $this->setCreateForm($task, new Role(TaskVoter::CREATE)); + + $form->handleRequest($request); + + if ($form->isSubmitted()) { + if ($form->isValid()) { + $em = $this->getDoctrine()->getManager(); + $em->persist($task); + + $this->eventDispatcher->dispatch(TaskEvent::PERSIST, new TaskEvent($task)); + + $em->flush(); + + $this->addFlash('success', $translator->trans('The task is created')); + + return $this->redirectToRoute('chill_task_singletask_list', [ + 'person_id' => $task->getPerson()->getId(), + ]); + } + $this->addFlash('error', $translator->trans('This form contains errors')); + } + + return $this->render('ChillTaskBundle:SingleTask:new.html.twig', [ + 'form' => $form->createView(), + 'task' => $task, + ]); + } + + /** + * @Route( + * "/{_locale}/task/single-task/{id}/show", + * name="chill_task_single_task_show" + * ) + * + * @param mixed $id + */ + public function showAction(Request $request, $id) + { + $em = $this->getDoctrine()->getManager(); + $task = $em->getRepository(SingleTask::class)->find($id); + + if ($task->getPerson() !== null) { + $personId = $task->getPerson()->getId(); + + if (null === $personId) { + return new Response('You must provide a person_id', Response::HTTP_BAD_REQUEST); + } + + $person = $this->getDoctrine()->getManager() + ->getRepository(Person::class) + ->find($personId); + + if (null === $person) { + throw $this->createNotFoundException('Invalid person id'); + } + } + $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task, 'You are not ' + . 'allowed to view this task'); + + if (!$task) { + throw $this->createNotFoundException('Unable to find Task entity.'); + } + + $timeline = $this->timelineBuilder + ->getTimelineHTML('task', ['task' => $task]); + + $event = new PrivacyEvent($person, [ + 'element_class' => SingleTask::class, + 'element_id' => $task->getId(), + 'action' => 'show', + ]); + $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); + + return $this->render('ChillTaskBundle:SingleTask:show.html.twig', [ + 'task' => $task, + 'timeline' => $timeline, + ]); + } protected function getPersonParam(Request $request, EntityManagerInterface $em) { $person = $em->getRepository(Person::class) - ->find($request->query->getInt('person_id')) - ; + ->find($request->query->getInt('person_id')); - if (NULL === $person) { + if (null === $person) { throw $this->createNotFoundException('person not found'); } - $this->denyAccessUnlessGranted(PersonVoter::SEE, $person, "You are " - . "not allowed to see this person"); + $this->denyAccessUnlessGranted(PersonVoter::SEE, $person, 'You are ' + . 'not allowed to see this person'); return $person; } @@ -594,16 +570,30 @@ class SingleTaskController extends AbstractController protected function getUserParam(Request $request, EntityManagerInterface $em) { $user = $em->getRepository(User::class) - ->find($request->query->getInt('user_id')) - ; + ->find($request->query->getInt('user_id')); - if (NULL === $user) { + if (null === $user) { throw $this->createNotFoundException('user not found'); } return $user; } + /** + * @return \Symfony\Component\Form\FormInterface + */ + protected function setCreateForm(SingleTask $task, Role $role) + { + $form = $this->createForm(SingleTaskType::class, $task, [ + 'center' => $task->getCenter(), + 'role' => $role, + ]); + + $form->add('submit', SubmitType::class); + + return $form; + } + /** * Creates a form to delete a Task entity by id. * @@ -616,11 +606,10 @@ class SingleTaskController extends AbstractController return $this->createFormBuilder() ->setAction($this->generateUrl( 'chill_task_single_task_delete', - array('id' => $id))) + ['id' => $id] + )) ->setMethod('DELETE') - ->add('submit', SubmitType::class, array('label' => 'Delete')) - ->getForm() - ; + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); } - } diff --git a/src/Bundle/ChillTaskBundle/Controller/TaskController.php b/src/Bundle/ChillTaskBundle/Controller/TaskController.php index 0c2b1f8d2..3b868812d 100644 --- a/src/Bundle/ChillTaskBundle/Controller/TaskController.php +++ b/src/Bundle/ChillTaskBundle/Controller/TaskController.php @@ -1,45 +1,49 @@ find($taskId) - ; + ->find($taskId); $defaultReturnPath = $this->generateUrl( 'chill_task_single_task_show', - [ + [ 'id' => $task->getId(), - 'list_params' => $request->query->get('list_params', []) - ]); + 'list_params' => $request->query->get('list_params', []), + ] + ); $defaultTemplate = '@ChillTask/SingleTask/transition.html.twig'; + break; + default: - return new Response("The type '$kind' is not implemented", - Response::HTTP_BAD_REQUEST); + return new Response( + "The type '{$kind}' is not implemented", + Response::HTTP_BAD_REQUEST + ); } - if (NULL === $task) { - throw $this->createNotFoundException("task with id '$taskId' and type " - . "'$type' does not exists"); + if (null === $task) { + throw $this->createNotFoundException("task with id '{$taskId}' and type " + . "'{$type}' does not exists"); } - + $workflow = $registry->get($task); - + if (!$workflow->can($task, $transition)) { throw $this->createAccessDeniedException('You are not allowed to apply this transition'); } - $transitionInstance = \array_values( // array_values needed to reset keys (array_filter preserves keys) - \array_filter( - $workflow->getEnabledTransitions($task), - function(Transition $t) use ($transition) { - return $t->getName() === $transition; - } - ))[0]; - - $form = $this->createTransitionForm($task); - - $form->handleRequest($request); - - if ($form->isSubmitted() && $form->isValid()) { + $transitionInstance = array_values( // array_values needed to reset keys (array_filter preserves keys) + array_filter( + $workflow->getEnabledTransitions($task), + function (Transition $t) use ($transition) { + return $t->getName() === $transition; + } + ) + )[0]; + $form = $this->createTransitionForm($task); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { if ($workflow->can($task, $transition)) { $workflow->apply($task, $transition); $em->flush(); $this->addFlash('success', $translator->trans('The transition is successfully applied')); - } else { $this->addFlash('error', $translator->trans('The transition could not be applied')); } - + return $this->redirect($defaultReturnPath); - } else { - $event = (new UIEvent($kind, $task)) - ->setForm($form) - ->setTransition($transitionInstance) - ; - - $eventDispatcher->dispatch(UIEvent::SHOW_TRANSITION_PAGE, $event); - - if ($event->hasResponse()) { - return $event->getResponse(); - } else { - // we simply check that the user can see the task. Other ACL checks - // should be performed using `guard` events. - $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task); - - return $this->render($defaultTemplate, [ - 'task' => $task, - 'form' => $form->createView(), - 'transition' => $transitionInstance - ]); - } } + $event = (new UIEvent($kind, $task)) + ->setForm($form) + ->setTransition($transitionInstance); + + $eventDispatcher->dispatch(UIEvent::SHOW_TRANSITION_PAGE, $event); + + if ($event->hasResponse()) { + return $event->getResponse(); + } + // we simply check that the user can see the task. Other ACL checks + // should be performed using `guard` events. + $this->denyAccessUnlessGranted(TaskVoter::SHOW, $task); + + return $this->render($defaultTemplate, [ + 'task' => $task, + 'form' => $form->createView(), + 'transition' => $transitionInstance, + ]); } - + /** - * * @param \Chill\TaskBundle\Controller\AbstractTask $task + * * @return \Symfony\Component\Form\FormInterface */ protected function createTransitionForm(AbstractTask $task) { $builder = $this->createFormBuilder($task); $builder->add('submit', SubmitType::class); - + return $builder->getForm(); } } diff --git a/src/Bundle/ChillTaskBundle/DataFixtures/ORM/LoadTaskACL.php b/src/Bundle/ChillTaskBundle/DataFixtures/ORM/LoadTaskACL.php index 5af11f6a2..fe1ed636f 100644 --- a/src/Bundle/ChillTaskBundle/DataFixtures/ORM/LoadTaskACL.php +++ b/src/Bundle/ChillTaskBundle/DataFixtures/ORM/LoadTaskACL.php @@ -1,37 +1,25 @@ +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\TaskBundle\DataFixtures\ORM; +use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; +use Chill\MainBundle\DataFixtures\ORM\LoadScopes; +use Chill\MainBundle\Entity\RoleScope; +use Chill\TaskBundle\Security\Authorization\TaskVoter; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Doctrine\Persistence\ObjectManager; -use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup; -use Chill\MainBundle\Entity\RoleScope; -use Chill\MainBundle\DataFixtures\ORM\LoadScopes; -use Chill\TaskBundle\Security\Authorization\TaskVoter; /** * Add a role UPDATE & CREATE for all groups except administrative, - * and a role SEE for administrative - * - * @author Julien Fastré + * and a role SEE for administrative. */ class LoadTaskACL extends AbstractFixture implements OrderedFixtureInterface { @@ -40,12 +28,12 @@ class LoadTaskACL extends AbstractFixture implements OrderedFixtureInterface return 16000; } - public function load(ObjectManager $manager) { foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) { $permissionsGroup = $this->getReference($permissionsGroupRef); - foreach (LoadScopes::$references as $scopeRef){ + + foreach (LoadScopes::$references as $scopeRef) { $scope = $this->getReference($scopeRef); //create permission group switch ($permissionsGroup->getName()) { @@ -53,39 +41,43 @@ class LoadTaskACL extends AbstractFixture implements OrderedFixtureInterface if ($scope->getName()['en'] === 'administrative') { break 2; // we do not want any power on administrative } + break; + case 'administrative': case 'direction': - if (in_array($scope->getName()['en'], array('administrative', 'social'))) { + if (in_array($scope->getName()['en'], ['administrative', 'social'])) { break 2; // we do not want any power on social or administrative - } + } + break; } - - printf("Adding CHILL_TASK_TASK_UPDATE & CHILL_TASK_TASK_CREATE & Chill_TASK_TASK_DELETE permissions to %s " - . "permission group, scope '%s' \n", - $permissionsGroup->getName(), $scope->getName()['en']); + + printf( + 'Adding CHILL_TASK_TASK_UPDATE & CHILL_TASK_TASK_CREATE & Chill_TASK_TASK_DELETE permissions to %s ' + . "permission group, scope '%s' \n", + $permissionsGroup->getName(), + $scope->getName()['en'] + ); $roleScopeUpdate = (new RoleScope()) - ->setRole(TaskVoter::UPDATE) - ->setScope($scope); + ->setRole(TaskVoter::UPDATE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeUpdate); $roleScopeCreate = (new RoleScope()) - ->setRole(TaskVoter::CREATE) - ->setScope($scope); + ->setRole(TaskVoter::CREATE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeCreate); $roleScopeDelete = (new RoleScope()) - ->setRole(TaskVoter::DELETE) - ->setScope($scope); + ->setRole(TaskVoter::DELETE) + ->setScope($scope); $permissionsGroup->addRoleScope($roleScopeDelete); - + $manager->persist($roleScopeUpdate); $manager->persist($roleScopeCreate); $manager->persist($roleScopeDelete); } - } - + $manager->flush(); } - } diff --git a/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php b/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php index 5ffbd38e7..990ea20be 100644 --- a/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php +++ b/src/Bundle/ChillTaskBundle/DependencyInjection/ChillTaskExtension.php @@ -1,31 +1,35 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services/controller.yaml'); $loader->load('services/security.yaml'); $loader->load('services/repositories.yaml'); @@ -44,29 +48,29 @@ class ChillTaskExtension extends Extension implements PrependExtensionInterface $this->prependRoute($container); $this->prependWorkflows($container); } - + + protected function prependAuthorization(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + TaskVoter::UPDATE => [TaskVoter::SHOW], + TaskVoter::CREATE => [TaskVoter::SHOW], + ], + ]); + } + protected function prependRoute(ContainerBuilder $container) { //declare routes for task bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillTaskBundle/config/routes.yaml' - ) - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillTaskBundle/config/routes.yaml', + ], + ], + ]); } - - protected function prependAuthorization(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - TaskVoter::UPDATE => [TaskVoter::SHOW], - TaskVoter::CREATE => [TaskVoter::SHOW] - ) - )); - } - + protected function prependWorkflows(ContainerBuilder $container) { $container->prependExtensionConfig('framework', [ @@ -75,29 +79,29 @@ class ChillTaskExtension extends Extension implements PrependExtensionInterface 'marking_store' => [ 'type' => 'multiple_state', 'arguments' => [ - 'currentStates' + 'currentStates', ], ], - 'type' => 'state_machine', + 'type' => 'state_machine', 'support_strategy' => TaskWorkflowManager::class, - 'places' => [ 'new', 'in_progress', 'closed', 'canceled'], + 'places' => ['new', 'in_progress', 'closed', 'canceled'], 'initial_place' => 'new', 'transitions' => [ 'start' => [ 'from' => 'new', - 'to' => 'in_progress' + 'to' => 'in_progress', ], 'close' => [ 'from' => ['new', 'in_progress'], - 'to' => 'closed' + 'to' => 'closed', ], 'cancel' => [ 'from' => ['new', 'in_progress'], - 'to' => 'canceled' - ] - ] - ] - ] + 'to' => 'canceled', + ], + ], + ], + ], ]); } } diff --git a/src/Bundle/ChillTaskBundle/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php b/src/Bundle/ChillTaskBundle/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php index 76e849d73..a3e51043c 100644 --- a/src/Bundle/ChillTaskBundle/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php +++ b/src/Bundle/ChillTaskBundle/DependencyInjection/Compiler/TaskWorkflowDefinitionCompilerPass.php @@ -1,47 +1,35 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\DependencyInjection\Compiler; - -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Chill\TaskBundle\Workflow\TaskWorkflowManager; -use Symfony\Component\DependencyInjection\Reference; -use Chill\TaskBundle\Templating\UI\CountNotificationTask; -use Chill\TaskBundle\Event\Lifecycle\TaskLifecycleEvent; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\DependencyInjection\Compiler; + +use Chill\TaskBundle\Event\Lifecycle\TaskLifecycleEvent; +use Chill\TaskBundle\Templating\UI\CountNotificationTask; +use Chill\TaskBundle\Workflow\TaskWorkflowManager; +use LogicException; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { if (!$container->hasDefinition(TaskWorkflowManager::class)) { - throw new \LogicException("The service ".TaskWorkflowManager::class." is " - . "not registered"); + throw new LogicException('The service ' . TaskWorkflowManager::class . ' is ' + . 'not registered'); } - + $workflowManagerDefinition = $container->getDefinition(TaskWorkflowManager::class); $counterDefinition = $container->getDefinition(CountNotificationTask::class); $lifecycleDefinition = $container->getDefinition(TaskLifecycleEvent::class); - + foreach ($container->findTaggedServiceIds('chill_task.workflow_definition') as $id => $tags) { // registering the definition to manager $workflowManagerDefinition @@ -50,21 +38,21 @@ class TaskWorkflowDefinitionCompilerPass implements CompilerPassInterface $definition = $container->getDefinition($id); $workflowManagerDefinition ->addTag('kernel.event_listener', [ - 'event' => sprintf('workflow.%s.entered', $definition->getClass()::getAssociatedWorkflowName()), - 'method' => 'onTaskStateEntered', - 'priority' => -255 - ]); + 'event' => sprintf('workflow.%s.entered', $definition->getClass()::getAssociatedWorkflowName()), + 'method' => 'onTaskStateEntered', + 'priority' => -255, + ]); $counterDefinition ->addTag('kernel.event_listener', [ 'event' => sprintf('workflow.%s.entered', $definition->getClass()::getAssociatedWorkflowName()), 'method' => 'resetCacheOnNewStates', - 'priority' => 0 + 'priority' => 0, ]); $lifecycleDefinition ->addTag('kernel.event_listener', [ 'event' => sprintf('workflow.%s.transition', $definition->getClass()::getAssociatedWorkflowName()), 'method' => 'onTransition', - 'priority' => 0 + 'priority' => 0, ]); } } diff --git a/src/Bundle/ChillTaskBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillTaskBundle/DependencyInjection/Configuration.php index 21d50c7f5..3a43bfcc2 100644 --- a/src/Bundle/ChillTaskBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillTaskBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ type = (string) $type; + return $this->assignee; + } - return $this; + public function getCenter(): ?\Chill\MainBundle\Entity\Center + { + if ($this->getPerson() instanceof Person) { + return $this->getPerson()->getCenter(); + } + + return null; + } + + public function getCircle(): ?Scope + { + return $this->circle; } /** - * Get type + * Get currentStates. + * + * The states are returned as required by marking store format. + * + * @return array + */ + public function getCurrentStates() + { + return array_fill_keys($this->currentStates, 1); + } + + /** + * Get description. + * + * @return string + */ + public function getDescription() + { + return $this->description; + } + + public function getPerson(): ?Person + { + return $this->person; + } + + public function getScope(): ?Scope + { + return $this->getCircle(); + } + + /** + * Get title. + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Get type. * * @return string */ @@ -116,9 +168,33 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface return $this->type; } + public function isClosed(): bool + { + return $this->closed; + } + + public function setAssignee(?User $assignee = null) + { + $this->assignee = $assignee; + + return $this; + } + + public function setCircle(Scope $circle) + { + $this->circle = $circle; + + return $this; + } + + public function setClosed(bool $closed) + { + $this->closed = $closed; + } + /** - * Set currentStates - * + * Set currentStates. + * * The current states are sorted in a single array, non associative. * * @param $currentStates @@ -127,25 +203,34 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface */ public function setCurrentStates($currentStates) { - $this->currentStates = \array_keys($currentStates); + $this->currentStates = array_keys($currentStates); return $this; } /** - * Get currentStates - * - * The states are returned as required by marking store format. + * Set description. * - * @return array + * @param string $description + * + * @return AbstractTask */ - public function getCurrentStates() + public function setDescription($description) { - return \array_fill_keys($this->currentStates, 1); + $this->description = (string) $description; + + return $this; + } + + public function setPerson(Person $person) + { + $this->person = $person; + + return $this; } /** - * Set title + * Set title. * * @param string $title * @@ -159,102 +244,16 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface } /** - * Get title + * Set type. * - * @return string - */ - public function getTitle() - { - return $this->title; - } - - /** - * Set description - * - * @param string $description + * @param string $type * * @return AbstractTask */ - public function setDescription($description) + public function setType($type) { - $this->description = (string) $description; + $this->type = (string) $type; return $this; } - - /** - * Get description - * - * @return string - */ - public function getDescription() - { - return $this->description; - } - - public function getAssignee(): ?User - { - return $this->assignee; - } - - public function getPerson(): ?Person - { - return $this->person; - } - - public function getCircle(): ?Scope - { - return $this->circle; - } - - public function setAssignee(User $assignee = null) - { - $this->assignee = $assignee; - return $this; - } - - public function setPerson(Person $person) - { - $this->person = $person; - return $this; - } - - public function setCircle(Scope $circle) - { - $this->circle = $circle; - return $this; - } - - public function getCenter(): ?\Chill\MainBundle\Entity\Center - { - if ($this->getPerson() instanceof Person) { - return $this->getPerson()->getCenter(); - } - - return null; - - } - - public function getScope(): ?\Chill\MainBundle\Entity\Scope - { - return $this->getCircle(); - } - - /** - * @return bool - */ - public function isClosed(): bool - { - return $this->closed; - } - - /** - * - * @param bool $closed - */ - public function setClosed(bool $closed) - { - $this->closed = $closed; - } } - diff --git a/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php b/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php index 20bffab18..ee182ef37 100644 --- a/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/RecurringTask.php @@ -1,20 +1,34 @@ singleTasks = new ArrayCollection(); } - /** - * Get id + * Get firstOccurenceEndDate. + * + * @return DateTime + */ + public function getFirstOccurenceEndDate() + { + return $this->firstOccurenceEndDate; + } + + /** + * Get id. * * @return int */ @@ -88,9 +102,49 @@ class RecurringTask extends AbstractTask } /** - * Set firstOccurenceEndDate + * Get lastOccurenceEndDate. * - * @param \DateTime $firstOccurenceEndDate + * @return DateTime + */ + public function getLastOccurenceEndDate() + { + return $this->lastOccurenceEndDate; + } + + /** + * Get occurenceFrequency. + * + * @return string + */ + public function getOccurenceFrequency() + { + return $this->occurenceFrequency; + } + + /** + * Get occurenceStartDate. + * + * @return dateinterval + */ + public function getOccurenceStartDate() + { + return $this->occurenceStartDate; + } + + /** + * Get occurenceWarningInterval. + * + * @return dateinterval + */ + public function getOccurenceWarningInterval() + { + return $this->occurenceWarningInterval; + } + + /** + * Set firstOccurenceEndDate. + * + * @param DateTime $firstOccurenceEndDate * * @return RecurringTask */ @@ -102,19 +156,9 @@ class RecurringTask extends AbstractTask } /** - * Get firstOccurenceEndDate + * Set lastOccurenceEndDate. * - * @return \DateTime - */ - public function getFirstOccurenceEndDate() - { - return $this->firstOccurenceEndDate; - } - - /** - * Set lastOccurenceEndDate - * - * @param \DateTime $lastOccurenceEndDate + * @param DateTime $lastOccurenceEndDate * * @return RecurringTask */ @@ -126,17 +170,7 @@ class RecurringTask extends AbstractTask } /** - * Get lastOccurenceEndDate - * - * @return \DateTime - */ - public function getLastOccurenceEndDate() - { - return $this->lastOccurenceEndDate; - } - - /** - * Set occurenceFrequency + * Set occurenceFrequency. * * @param string $occurenceFrequency * @@ -150,17 +184,7 @@ class RecurringTask extends AbstractTask } /** - * Get occurenceFrequency - * - * @return string - */ - public function getOccurenceFrequency() - { - return $this->occurenceFrequency; - } - - /** - * Set occurenceStartDate + * Set occurenceStartDate. * * @param dateinterval $occurenceStartDate * @@ -174,17 +198,7 @@ class RecurringTask extends AbstractTask } /** - * Get occurenceStartDate - * - * @return dateinterval - */ - public function getOccurenceStartDate() - { - return $this->occurenceStartDate; - } - - /** - * Set occurenceWarningInterval + * Set occurenceWarningInterval. * * @param dateinterval $occurenceWarningInterval * @@ -196,15 +210,4 @@ class RecurringTask extends AbstractTask return $this; } - - /** - * Get occurenceWarningInterval - * - * @return dateinterval - */ - public function getOccurenceWarningInterval() - { - return $this->occurenceWarningInterval; - } } - diff --git a/src/Bundle/ChillTaskBundle/Entity/SingleTask.php b/src/Bundle/ChillTaskBundle/Entity/SingleTask.php index 23bdd61df..cf1eaa119 100644 --- a/src/Bundle/ChillTaskBundle/Entity/SingleTask.php +++ b/src/Bundle/ChillTaskBundle/Entity/SingleTask.php @@ -1,31 +1,49 @@ this.getStartDate()", - * message="The start date must be before warning date" + * "value === null or this.getWarningDate() === null or this.getWarningDate() > this.getStartDate()", + * message="The start date must be before warning date" * ) */ private $startDate; /** - * @var \DateTime - * - * @ORM\Column(name="end_date", type="date", nullable=true) - * @Assert\Date() - */ - private $endDate; - - /** - * @var \DateInterval - * and this.getEndDate() === null - * - * @ORM\Column(name="warning_interval", type="dateinterval", nullable=true) - * - * @Assert\Expression( - * "!(value != null and this.getEndDate() == null)", - * message="An end date is required if a warning interval is set" - * ) - * - * - */ - private $warningInterval; - - /** - * - * @var RecurringTask - * @ORM\ManyToOne( - * targetEntity="RecurringTask", - * inversedBy="singleTasks" - * ) - */ - private $recurringTask; - - /** - * * @var \Doctrine\Common\Collections\Collection * @ORM\OneToMany( - * targetEntity="\Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent", - * mappedBy="task", - * cascade={ "remove" } + * targetEntity="\Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent", + * mappedBy="task", + * cascade={ "remove" } * ) */ private $taskPlaceEvents; - + + /** + * @var DateInterval + * and this.getEndDate() === null + * + * @ORM\Column(name="warning_interval", type="dateinterval", nullable=true) + * + * @Assert\Expression( + * "!(value != null and this.getEndDate() == null)", + * message="An end date is required if a warning interval is set" + * ) + */ + private $warningInterval; + public function __construct() { - $this->taskPlaceEvents = $events = new \Doctrine\Common\Collections\ArrayCollection; - + $this->taskPlaceEvents = $events = new \Doctrine\Common\Collections\ArrayCollection(); + parent::__construct(); } - /** - * Get id + * Get endDate. + * + * @return DateTime + */ + public function getEndDate() + { + return $this->endDate; + } + + /** + * Get id. * * @return int */ @@ -115,34 +130,62 @@ class SingleTask extends AbstractTask return $this->id; } - /** - * Set startDate - * - * @param \DateTime $startDate - * - * @return SingleTask - */ - public function setStartDate($startDate) + public function getRecurringTask(): RecurringTask { - $this->startDate = $startDate; - - return $this; + return $this->recurringTask; } /** - * Get startDate + * Get startDate. * - * @return \DateTime + * @return DateTime */ public function getStartDate() { return $this->startDate; } + public function getTaskPlaceEvents(): Collection + { + return $this->taskPlaceEvents; + } + /** - * Set endDate + * Get the Warning date, computed from the difference between the + * end date and the warning interval. * - * @param \DateTime $endDate + * Return null if warningDate or endDate is null + * + * @return DateTimeImmutable + */ + public function getWarningDate() + { + if ($this->getWarningInterval() === null) { + return null; + } + + if ($this->getEndDate() === null) { + return null; + } + + return DateTimeImmutable::createFromMutable($this->getEndDate()) + ->sub($this->getWarningInterval()); + } + + /** + * Get warningInterval. + * + * @return DateInterval + */ + public function getWarningInterval() + { + return $this->warningInterval; + } + + /** + * Set endDate. + * + * @param DateTime $endDate * * @return SingleTask */ @@ -153,18 +196,34 @@ class SingleTask extends AbstractTask return $this; } - /** - * Get endDate - * - * @return \DateTime - */ - public function getEndDate() + public function setRecurringTask(RecurringTask $recurringTask) { - return $this->endDate; + $this->recurringTask = $recurringTask; } /** - * Set warningInterval + * Set startDate. + * + * @param DateTime $startDate + * + * @return SingleTask + */ + public function setStartDate($startDate) + { + $this->startDate = $startDate; + + return $this; + } + + public function setTaskPlaceEvents(Collection $taskPlaceEvents) + { + $this->taskPlaceEvents = $taskPlaceEvents; + + return $this; + } + + /** + * Set warningInterval. * * @param string $warningInterval * @@ -176,59 +235,4 @@ class SingleTask extends AbstractTask return $this; } - - /** - * Get warningInterval - * - * @return \DateInterval - */ - public function getWarningInterval() - { - return $this->warningInterval; - } - - /** - * Get the Warning date, computed from the difference between the - * end date and the warning interval - * - * Return null if warningDate or endDate is null - * - * @return \DateTimeImmutable - */ - public function getWarningDate() - { - if ($this->getWarningInterval() === null) { - return null; - } - - if ($this->getEndDate() === null) { - return null; - } - - return \DateTimeImmutable::createFromMutable($this->getEndDate()) - ->sub($this->getWarningInterval()); - } - - function getRecurringTask(): RecurringTask - { - return $this->recurringTask; - } - - function setRecurringTask(RecurringTask $recurringTask) - { - $this->recurringTask = $recurringTask; - } - - public function getTaskPlaceEvents(): Collection - { - return $this->taskPlaceEvents; - } - - public function setTaskPlaceEvents(Collection $taskPlaceEvents) - { - $this->taskPlaceEvents = $taskPlaceEvents; - - return $this; - } } - diff --git a/src/Bundle/ChillTaskBundle/Entity/Task/AbstractTaskPlaceEvent.php b/src/Bundle/ChillTaskBundle/Entity/Task/AbstractTaskPlaceEvent.php index 91ce89a15..788569a81 100644 --- a/src/Bundle/ChillTaskBundle/Entity/Task/AbstractTaskPlaceEvent.php +++ b/src/Bundle/ChillTaskBundle/Entity/Task/AbstractTaskPlaceEvent.php @@ -1,17 +1,47 @@ datetime = new \DateTimeImmutable('now'); + $this->datetime = new DateTimeImmutable('now'); } - /** - * Get id. - * - * @return int - */ - public function getId() + public function getAuthor(): User { - return $this->id; + return $this->author; } /** - * Set datetime. + * Get data. * - * @param datetime_immutable $datetime - * - * @return AbstractTaskPlaceEvent + * @return string */ - public function setDatetime($datetime) + public function getData() { - $this->datetime = $datetime; - - return $this; + return $this->data; } /** @@ -91,17 +89,13 @@ class AbstractTaskPlaceEvent } /** - * Set transition. + * Get id. * - * @param string $transition - * - * @return AbstractTaskPlaceEvent + * @return int */ - public function setTransition($transition) + public function getId() { - $this->transition = $transition; - - return $this; + return $this->id; } /** @@ -114,6 +108,13 @@ class AbstractTaskPlaceEvent return $this->transition; } + public function setAuthor(User $author) + { + $this->author = $author; + + return $this; + } + /** * Set data. * @@ -129,26 +130,30 @@ class AbstractTaskPlaceEvent } /** - * Get data. + * Set datetime. * - * @return string + * @param datetime_immutable $datetime + * + * @return AbstractTaskPlaceEvent */ - public function getData() + public function setDatetime($datetime) { - return $this->data; - } - - public function getAuthor(): User - { - return $this->author; - } + $this->datetime = $datetime; - public function setAuthor(User $author) - { - $this->author = $author; - return $this; } + /** + * Set transition. + * + * @param string $transition + * + * @return AbstractTaskPlaceEvent + */ + public function setTransition($transition) + { + $this->transition = $transition; + return $this; + } } diff --git a/src/Bundle/ChillTaskBundle/Entity/Task/SingleTaskPlaceEvent.php b/src/Bundle/ChillTaskBundle/Entity/Task/SingleTaskPlaceEvent.php index fe8d2583e..5c6cd44d0 100644 --- a/src/Bundle/ChillTaskBundle/Entity/Task/SingleTaskPlaceEvent.php +++ b/src/Bundle/ChillTaskBundle/Entity/Task/SingleTaskPlaceEvent.php @@ -1,56 +1,43 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Entity\Task; - -use Doctrine\ORM\Mapping as ORM; -use Chill\TaskBundle\Entity\SingleTask; /** - * + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\TaskBundle\Entity\Task; + +use Chill\TaskBundle\Entity\SingleTask; +use Doctrine\ORM\Mapping as ORM; + +/** * @ORM\Table( - * name="chill_task.single_task_place_event", - * indexes={ - * @ORM\Index( - * name="transition_task_date", - * columns={"task_id", "transition", "datetime"} - * ), - * @ORM\Index( - * name="transition_task", - * columns={"task_id", "transition"} - * ) - * }) - * @ORM\Entity() - * - * @author Julien Fastré + * name="chill_task.single_task_place_event", + * indexes={ + * @ORM\Index( + * name="transition_task_date", + * columns={"task_id", "transition", "datetime"} + * ), + * @ORM\Index( + * name="transition_task", + * columns={"task_id", "transition"} + * ) + * }) + * @ORM\Entity */ class SingleTaskPlaceEvent extends AbstractTaskPlaceEvent { /** - * * @var SingleTask * @ORM\ManyToOne( - * targetEntity="\Chill\TaskBundle\Entity\SingleTask", - * inversedBy="taskPlaceEvents" + * targetEntity="\Chill\TaskBundle\Entity\SingleTask", + * inversedBy="taskPlaceEvents" * ) */ protected $task; - + public function getTask(): SingleTask { return $this->task; @@ -59,9 +46,7 @@ class SingleTaskPlaceEvent extends AbstractTaskPlaceEvent public function setTask(SingleTask $task) { $this->task = $task; - + return $this; } - - } diff --git a/src/Bundle/ChillTaskBundle/Event/Lifecycle/TaskLifecycleEvent.php b/src/Bundle/ChillTaskBundle/Event/Lifecycle/TaskLifecycleEvent.php index 74bd33cc9..7bb63749a 100644 --- a/src/Bundle/ChillTaskBundle/Event/Lifecycle/TaskLifecycleEvent.php +++ b/src/Bundle/ChillTaskBundle/Event/Lifecycle/TaskLifecycleEvent.php @@ -1,90 +1,73 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Event\Lifecycle; - -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Chill\TaskBundle\Event\TaskEvent; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; -use Symfony\Component\Workflow\Event\Event as WorkflowEvent; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Event\Lifecycle; + +use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; +use Chill\TaskBundle\Event\TaskEvent; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Workflow\Event\Event as WorkflowEvent; + class TaskLifecycleEvent implements EventSubscriberInterface { /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; - - /** - * * @var EntityManagerInterface */ protected $em; - + + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + public function __construct( - TokenStorageInterface $tokenStorage, + TokenStorageInterface $tokenStorage, EntityManagerInterface $em ) { $this->tokenStorage = $tokenStorage; $this->em = $em; } - public static function getSubscribedEvents(): array { return [ TaskEvent::PERSIST => [ - 'onTaskPersist' - ] + 'onTaskPersist', + ], ]; } - + public function onTaskPersist(TaskEvent $e) { $task = $e->getTask(); $user = $this->tokenStorage->getToken()->getUser(); - + $event = (new SingleTaskPlaceEvent()) ->setTask($task) ->setAuthor($user) ->setTransition('_creation') ->setData([ - 'new_states' => $task->getCurrentStates() - ]) - ; - + 'new_states' => $task->getCurrentStates(), + ]); + $task->getTaskPlaceEvents()->add($event); - + $this->em->persist($event); } - + public function onTransition(WorkflowEvent $e) { $task = $e->getSubject(); $user = $this->tokenStorage->getToken()->getUser(); - + $event = (new SingleTaskPlaceEvent()) ->setTask($task) ->setAuthor($user) @@ -92,13 +75,11 @@ class TaskLifecycleEvent implements EventSubscriberInterface ->setData([ 'old_states' => $e->getTransition()->getFroms(), 'new_states' => $e->getTransition()->getTos(), - 'workflow' => $e->getWorkflowName() - ]) - ; - + 'workflow' => $e->getWorkflowName(), + ]); + $task->getTaskPlaceEvents()->add($event); - + $this->em->persist($event); } - } diff --git a/src/Bundle/ChillTaskBundle/Event/TaskEvent.php b/src/Bundle/ChillTaskBundle/Event/TaskEvent.php index 070118c4d..87187643f 100644 --- a/src/Bundle/ChillTaskBundle/Event/TaskEvent.php +++ b/src/Bundle/ChillTaskBundle/Event/TaskEvent.php @@ -1,45 +1,31 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Event; use Chill\TaskBundle\Entity\AbstractTask; use Symfony\Component\EventDispatcher\Event; -/** - * - * - * @author Julien Fastré - */ class TaskEvent extends Event { - const PERSIST = 'chill_task.task_persist'; - + public const PERSIST = 'chill_task.task_persist'; + /** - * * @var AbstractTask */ protected $task; - + public function __construct(AbstractTask $task) { $this->task = $task; } - + public function getTask(): AbstractTask { return $this->task; @@ -48,8 +34,7 @@ class TaskEvent extends Event public function setTask(AbstractTask $task) { $this->task = $task; - + return $this; } } - diff --git a/src/Bundle/ChillTaskBundle/Event/UI/UIEvent.php b/src/Bundle/ChillTaskBundle/Event/UI/UIEvent.php index e041da542..7ff66c476 100644 --- a/src/Bundle/ChillTaskBundle/Event/UI/UIEvent.php +++ b/src/Bundle/ChillTaskBundle/Event/UI/UIEvent.php @@ -1,81 +1,60 @@ + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Event\UI; + +use Chill\TaskBundle\Entity\AbstractTask; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Workflow\Transition; + class UIEvent extends Event { - const SHOW_TRANSITION_PAGE = 'chill_task.show_transition_page'; - const EDIT_FORM = 'chill_task.edit_form'; - const EDIT_PAGE = 'chill_task.edit_page'; - + public const EDIT_FORM = 'chill_task.edit_form'; + + public const EDIT_PAGE = 'chill_task.edit_page'; + + public const SHOW_TRANSITION_PAGE = 'chill_task.show_transition_page'; + + /** + * @var FormInterface|null + */ + protected $form; + /** - * * @var string */ protected $kind; - + /** - * - * @var AbstractTask - */ - protected $task; - - /** - * * @var Response|null */ - protected $response = null; - + protected $response; + /** - * - * @var FormInterface|null + * @var AbstractTask */ - protected $form = null; - + protected $task; + /** * @var Transition */ - protected $transition = null; - + protected $transition; + public function __construct($kind, AbstractTask $task) { $this->kind = $kind; $this->task = $task; } - - /** - * - * @return string - */ - public function getKind() - { - return $this->kind; - } /** - * - * @return AbstractTask - */ - public function getTask(): AbstractTask - { - return $this->task; - } - - /** - * * @return FormInterface|null */ public function getForm() @@ -83,15 +62,25 @@ class UIEvent extends Event return $this->form; } - public function setForm(FormInterface $form) - { - $this->form = $form; - - return $this; - } - /** - * + * @return string + */ + public function getKind() + { + return $this->kind; + } + + public function getResponse(): Response + { + return $this->response; + } + + public function getTask(): AbstractTask + { + return $this->task; + } + + /** * @return Transition */ public function getTransition() @@ -99,38 +88,32 @@ class UIEvent extends Event return $this->transition; } - public function setTransition(Transition $transition) - { - $this->transition = $transition; - - return $this; - } - - /** - * - * @return Response - */ - public function getResponse(): Response - { - return $this->response; - } - - /** - * - * @param Response $response - * @return $this - */ - public function setResponse(Response $response) - { - $this->response = $response; - - return $this; - } - public function hasResponse() { return $this->response instanceof Response; } + public function setForm(FormInterface $form) + { + $this->form = $form; + return $this; + } + + /** + * @return $this + */ + public function setResponse(Response $response) + { + $this->response = $response; + + return $this; + } + + public function setTransition(Transition $transition) + { + $this->transition = $transition; + + return $this; + } } diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php index 99e8ddb42..7c31d4874 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskListType.php @@ -1,75 +1,61 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Form; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Bridge\Doctrine\Form\Type\EntityType; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; -use Chill\TaskBundle\Repository\SingleTaskRepository; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Doctrine\ORM\EntityManagerInterface; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\TaskBundle\Security\Authorization\TaskVoter; -use Symfony\Component\Security\Core\Role\Role; -use Chill\TaskBundle\Entity\SingleTask; -use Chill\PersonBundle\Form\Type\PickPersonType; -use Chill\PersonBundle\Entity\Person; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; -use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; -use Chill\TaskBundle\Workflow\TaskWorkflowManager; /** + * Chill is a software for social workers * - * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Form; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Form\DataTransformer\PersonToIdTransformer; +use Chill\PersonBundle\Form\Type\PickPersonType; +use Chill\TaskBundle\Entity\SingleTask; +use Chill\TaskBundle\Repository\SingleTaskRepository; +use Chill\TaskBundle\Security\Authorization\TaskVoter; +use Chill\TaskBundle\Workflow\TaskWorkflowManager; +use Doctrine\ORM\EntityManagerInterface; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Role\Role; + +use function array_combine; +use function array_map; + class SingleTaskListType extends AbstractType { /** - * - * @var EntityManagerInterface - */ - protected $em; - - /** - * - * @var TokenStorageInterface - */ - protected $tokenStorage; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var EntityManagerInterface + */ + protected $em; + /** - * * @var TaskWorkflowManager */ protected $taskWorkflowManager; - + + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + public function __construct( - EntityManagerInterface $em, - TokenStorageInterface $tokenStorage, + EntityManagerInterface $em, + TokenStorageInterface $tokenStorage, AuthorizationHelper $authorizationHelper, TaskWorkflowManager $taskWorkflowManager ) { @@ -79,7 +65,6 @@ class SingleTaskListType extends AbstractType $this->taskWorkflowManager = $taskWorkflowManager; } - public function buildForm(FormBuilderInterface $builder, array $options) { $statuses = [ @@ -87,56 +72,54 @@ class SingleTaskListType extends AbstractType 'Tasks with expired deadline' => SingleTaskRepository::DATE_STATUS_ENDED, 'Tasks with warning deadline reached' => SingleTaskRepository::DATE_STATUS_WARNING, 'Current tasks' => SingleTaskRepository::DATE_STATUS_CURRENT, - 'Closed tasks' => 'closed' + 'Closed tasks' => 'closed', ]; - + $builder ->add('user_id', ChoiceType::class, [ 'choices' => $this->getUserChoices($options), 'placeholder' => 'Any user', 'required' => false, - 'label' => 'Assignee' - ]) - ; - + 'label' => 'Assignee', + ]); + if ($options['add_status']) { $builder ->add('status', ChoiceType::class, [ 'choices' => $statuses, 'expanded' => true, 'multiple' => true, - 'label' => 'status' + 'label' => 'status', ]); } - + if ($options['add_type']) { $types = $this->getTaskTypesChoices($options); - + if (count($types) > 0) { $builder->add('types', ChoiceType::class, [ 'choices' => $types, 'required' => false, 'expanded' => true, 'multiple' => true, - 'label' => 'Task types' + 'label' => 'Task types', ]); } - } - - if ($options['person'] === null) { + + if (null === $options['person']) { $builder ->add('person_id', PickPersonType::class, [ 'centers' => $this->authorizationHelper ->getReachableCenters( $this->tokenStorage->getToken()->getUser(), new Role(TaskVoter::SHOW) - ), + ), 'required' => false, - 'label' => 'Associated person' - ]) - ; + 'label' => 'Associated person', + ]); $reachablesCenters = $this->getReachablesCenters(); + if (count($reachablesCenters) > 1) { $builder ->add('center_id', EntityType::class, [ @@ -144,7 +127,7 @@ class SingleTaskListType extends AbstractType 'choices' => $reachablesCenters, 'label' => 'Center', 'required' => false, - 'placeholder' => 'All centers' + 'placeholder' => 'All centers', ]); } } else { @@ -152,130 +135,8 @@ class SingleTaskListType extends AbstractType $builder ->add('person_id', HiddenType::class); $builder->get('person_id') - ->addModelTransformer(new PersonToIdTransformer($this->em)) - ; + ->addModelTransformer(new PersonToIdTransformer($this->em)); } - - } - - protected function getUserChoices($options) - { - $users = $this->getUsersAssigneedToTask($options); - $choices = \array_combine( - // get usernames - \array_map(function(User $user) { return $user->getUsername(); }, $users), - // get ids - \array_map(function(User $user) { return $user->getId(); }, $users) - ); - $choices['Unassigned'] = '_unassigned'; - - return $choices; - } - - protected function getTaskTypesChoices($options) - { - $qb = $this->em->createQueryBuilder(); - $user = $this->tokenStorage->getToken()->getUser(); - $role = new Role(TaskVoter::SHOW); - $centers = $this->authorizationHelper->getReachableCenters($user, $role); - - $qb->select('DISTINCT task.type AS type') - ->from(SingleTask::class, 'task') - ->join('task.person', 'person') - ; - - $i = 0; - $orCenters = $qb->expr()->orX(); - foreach($centers as $center) { - $circles = $this->authorizationHelper->getReachableCircles($user, $role, $center); - - if (count($circles) > 0) { - $andX = $qb->expr()->andX(); - $andX - ->add($qb->expr()->eq('person.center', ':center_'.$i)) - ->add($qb->expr()->in('task.circle', ':circles_'.$i)) - ; - $orCenters->add($andX); - - $qb - ->setParameter('center_'.$i, $center) - ->setParameter('circles_'.$i, $circles) - ; - $i++; - } - } - - if ($i > 0) { - $qb->where($orCenters); - } - - $types = $qb->getQuery()->getResult(); - - $choices = []; - - foreach ($types as $row) { - $fake = (new SingleTask())->setType($row['type']); - $label = $this->taskWorkflowManager->getWorkflowMetadata($fake, 'definition.name'); - $choices[$label] = $row['type']; - } - - return $choices; - } - - /** - * Return a list of user having a task assigned. - * - * @return User[] - */ - protected function getUsersAssigneedToTask($options) - { - $qb = $this->em->createQueryBuilder(); - $user = $this->tokenStorage->getToken()->getUser(); - $role = new Role(TaskVoter::SHOW); - $centers = $this->authorizationHelper->getReachableCenters($user, $role); - - $qb->select('DISTINCT user') - ->from(User::class, 'user') - ->join(SingleTask::class, 'task', \Doctrine\ORM\Query\Expr\Join::WITH, 'task.assignee = user') - ->join('task.person', 'person') - ->where("user.enabled = 'TRUE'") - ; - - if (NULL !== $options['person']) { - $qb - ->andWhere($qb->expr()->eq('task.person', ':person')) - ->setParameter('person', $options['person']) - ; - } - - $i = 0; - $circleCenterCond = $qb->expr()->orX(); - foreach ($centers as $center) { - $circles = $this->authorizationHelper->getReachableCircles($user, $role, $center); - // add condition about person and circle - $circleCenterCond->add( - $qb->expr()->andX() - ->add($qb->expr()->eq('person.center', ':center_'.$i)) - ->add($qb->expr()->in('task.circle', ':circles_'.$i)) - ); - - $qb->setParameter('center_'.$i, $center) - ->setParameter('circles_'.$i, $circles) - ; - // increase counter - $i++; - } - $qb->andWhere($circleCenterCond); - - return $qb->getQuery()->getResult(); - } - - protected function getReachablesCenters() - { - $user = $this->tokenStorage->getToken()->getUser(); - $role = new Role(TaskVoter::SHOW); - - return $this->authorizationHelper->getReachableCenters($user, $role); } public function configureOptions(OptionsResolver $resolver) @@ -289,7 +150,128 @@ class SingleTaskListType extends AbstractType ->setAllowedTypes('add_status', ['bool']) ->setDefined('add_type') ->setDefault('add_type', false) - ->setAllowedTypes('add_type', ['bool']) - ; + ->setAllowedTypes('add_type', ['bool']); + } + + protected function getReachablesCenters() + { + $user = $this->tokenStorage->getToken()->getUser(); + $role = new Role(TaskVoter::SHOW); + + return $this->authorizationHelper->getReachableCenters($user, $role); + } + + protected function getTaskTypesChoices($options) + { + $qb = $this->em->createQueryBuilder(); + $user = $this->tokenStorage->getToken()->getUser(); + $role = new Role(TaskVoter::SHOW); + $centers = $this->authorizationHelper->getReachableCenters($user, $role); + + $qb->select('DISTINCT task.type AS type') + ->from(SingleTask::class, 'task') + ->join('task.person', 'person'); + + $i = 0; + $orCenters = $qb->expr()->orX(); + + foreach ($centers as $center) { + $circles = $this->authorizationHelper->getReachableCircles($user, $role, $center); + + if (count($circles) > 0) { + $andX = $qb->expr()->andX(); + $andX + ->add($qb->expr()->eq('person.center', ':center_' . $i)) + ->add($qb->expr()->in('task.circle', ':circles_' . $i)); + $orCenters->add($andX); + + $qb + ->setParameter('center_' . $i, $center) + ->setParameter('circles_' . $i, $circles); + ++$i; + } + } + + if (0 < $i) { + $qb->where($orCenters); + } + + $types = $qb->getQuery()->getResult(); + + $choices = []; + + foreach ($types as $row) { + $fake = (new SingleTask())->setType($row['type']); + $label = $this->taskWorkflowManager->getWorkflowMetadata($fake, 'definition.name'); + $choices[$label] = $row['type']; + } + + return $choices; + } + + protected function getUserChoices($options) + { + $users = $this->getUsersAssigneedToTask($options); + $choices = array_combine( + // get usernames + array_map(function (User $user) { + return $user->getUsername(); + }, $users), + // get ids + array_map(function (User $user) { + return $user->getId(); + }, $users) + ); + $choices['Unassigned'] = '_unassigned'; + + return $choices; + } + + /** + * Return a list of user having a task assigned. + * + * @param mixed $options + * + * @return User[] + */ + protected function getUsersAssigneedToTask($options) + { + $qb = $this->em->createQueryBuilder(); + $user = $this->tokenStorage->getToken()->getUser(); + $role = new Role(TaskVoter::SHOW); + $centers = $this->authorizationHelper->getReachableCenters($user, $role); + + $qb->select('DISTINCT user') + ->from(User::class, 'user') + ->join(SingleTask::class, 'task', \Doctrine\ORM\Query\Expr\Join::WITH, 'task.assignee = user') + ->join('task.person', 'person') + ->where("user.enabled = 'TRUE'"); + + if (null !== $options['person']) { + $qb + ->andWhere($qb->expr()->eq('task.person', ':person')) + ->setParameter('person', $options['person']); + } + + $i = 0; + $circleCenterCond = $qb->expr()->orX(); + + foreach ($centers as $center) { + $circles = $this->authorizationHelper->getReachableCircles($user, $role, $center); + // add condition about person and circle + $circleCenterCond->add( + $qb->expr()->andX() + ->add($qb->expr()->eq('person.center', ':center_' . $i)) + ->add($qb->expr()->in('task.circle', ':circles_' . $i)) + ); + + $qb->setParameter('center_' . $i, $center) + ->setParameter('circles_' . $i, $circles); + // increase counter + ++$i; + } + $qb->andWhere($circleCenterCond); + + return $qb->getQuery()->getResult(); } } diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php index 16f000aa2..af535cd17 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php @@ -1,39 +1,26 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Form; - -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; -use Chill\MainBundle\Form\Type\ChillDateType; -use Chill\MainBundle\Entity\Center; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Chill\MainBundle\Form\Type\UserPickerType; -use Chill\MainBundle\Form\Type\ScopePickerType; -use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\Security\Core\Role\Role; -use Chill\MainBundle\Form\Type\DateIntervalType; -use Chill\MainBundle\Form\Type\ChillTextareaType; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Form; + +use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Form\Type\ChillDateType; +use Chill\MainBundle\Form\Type\ChillTextareaType; +use Chill\MainBundle\Form\Type\DateIntervalType; +use Chill\MainBundle\Form\Type\ScopePickerType; +use Chill\MainBundle\Form\Type\UserPickerType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Role\Role; + class SingleTaskType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) @@ -41,37 +28,35 @@ class SingleTaskType extends AbstractType $builder ->add('title', TextType::class) ->add('description', ChillTextareaType::class, [ - 'required' => false + 'required' => false, ]) ->add('assignee', UserPickerType::class, [ 'required' => false, 'center' => $options['center'], - 'role' => $options['role'], - 'placeholder' => 'Not assigned' + 'role' => $options['role'], + 'placeholder' => 'Not assigned', ]) ->add('circle', ScopePickerType::class, [ 'center' => $options['center'], - 'role' => $options['role'] + 'role' => $options['role'], ]) ->add('startDate', ChillDateType::class, [ - 'required' => false + 'required' => false, ]) ->add('endDate', ChillDateType::class, [ - 'required' => false + 'required' => false, ]) ->add('warningInterval', DateIntervalType::class, [ - 'required' => false - ]) - ; + 'required' => false, + ]); } - + public function configureOptions(OptionsResolver $resolver) { $resolver ->setRequired('center') - ->setAllowedTypes('center', [ Center::class ]) + ->setAllowedTypes('center', [Center::class]) ->setRequired('role') - ->setAllowedTypes('role', [ Role::class ]) - ; + ->setAllowedTypes('role', [Role::class]); } } diff --git a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php index ee0afa497..ba1949739 100644 --- a/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/PersonMenuBuilder.php @@ -1,73 +1,59 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\TaskBundle\Security\Authorization\TaskVoter; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\TaskBundle\Security\Authorization\TaskVoter; use Symfony\Component\Translation\TranslatorInterface; -/** - * - * - * @author Julien Fastré - */ class PersonMenuBuilder implements LocalMenuBuilderInterface { /** - * - * @var TranslatorInterface - */ - protected $translator; - - /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + + /** + * @var TranslatorInterface + */ + protected $translator; + public function __construct( AuthorizationCheckerInterface $authorizationChecker, - TranslatorInterface $translator) - { + TranslatorInterface $translator + ) { $this->translator = $translator; $this->authorizationChecker = $authorizationChecker; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { /* @var $person \Chill\PersonBundle\Entity\Person */ $person = $parameters['person'] ?? null; - + if ($this->authorizationChecker->isGranted(TaskVoter::SHOW, $person)) { $menu->addChild( - $this->translator->trans('Tasks'), [ + $this->translator->trans('Tasks'), + [ 'route' => 'chill_task_singletask_list', - 'routeParameters' => $menuId === 'person' ? - [ 'person_id' => $person->getId() ] + 'routeParameters' => 'person' === $menuId ? + ['person_id' => $person->getId()] : null, - ]) - ->setExtra('order', 400) - ; - if ($menuId === 'section') { + ] + ) + ->setExtra('order', 400); + + if ('section' === $menuId) { $menu->setExtra('icons', 'tasks'); } } diff --git a/src/Bundle/ChillTaskBundle/Menu/SectionMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/SectionMenuBuilder.php index 7ed84dbf5..c25f181e8 100644 --- a/src/Bundle/ChillTaskBundle/Menu/SectionMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/SectionMenuBuilder.php @@ -1,47 +1,32 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Menu; use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\TaskBundle\Security\Authorization\TaskVoter; use Knp\Menu\MenuItem; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\TaskBundle\Security\Authorization\TaskVoter; use Symfony\Component\Translation\TranslatorInterface; - -/** - * - * - */ class SectionMenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ public $authorizationChecker; - + /** - * * @var TranslatorInterface */ public $translator; - + public function __construct( AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator @@ -49,30 +34,31 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface $this->authorizationChecker = $authorizationChecker; $this->translator = $translator; } - + public function buildMenu($menuId, MenuItem $menu, array $parameters) { - if (FALSE === $this->authorizationChecker->isGranted(TaskVoter::SHOW)) { + if (false === $this->authorizationChecker->isGranted(TaskVoter::SHOW)) { return; } - + $menu->addChild( - $this->translator->trans("Tasks"), + $this->translator->trans('Tasks'), [ 'route' => 'chill_task_singletask_list', [ - 'routeParameters' => [ - 'hide_form' => false - ] - ]]) + 'routeParameters' => [ + 'hide_form' => false, + ], + ], ] + ) ->setExtras([ - 'order'=> 50, + 'order' => 50, 'icon' => 'exclamation-triangle', - 'entryclass' => 'user_menu__entry--warning-entry' + 'entryclass' => 'user_menu__entry--warning-entry', ]); } public static function getMenuIds(): array { - return [ 'section' ]; + return ['section']; } } diff --git a/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php b/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php index e29239679..b10395c8e 100644 --- a/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php +++ b/src/Bundle/ChillTaskBundle/Menu/UserMenuBuilder.php @@ -1,63 +1,46 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Menu; - -use Chill\MainBundle\Routing\LocalMenuBuilderInterface; -use Knp\Menu\MenuItem; -use Chill\TaskBundle\Templating\UI\CountNotificationTask; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\TaskBundle\Repository\SingleTaskRepository; -use Symfony\Component\Translation\TranslatorInterface; -use Chill\MainBundle\Entity\User; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\TaskBundle\Security\Authorization\TaskVoter; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Menu; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\TaskBundle\Repository\SingleTaskRepository; +use Chill\TaskBundle\Security\Authorization\TaskVoter; +use Chill\TaskBundle\Templating\UI\CountNotificationTask; +use Knp\Menu\MenuItem; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + class UserMenuBuilder implements LocalMenuBuilderInterface { - /** - * + * @var AuthorizationCheckerInterface + */ + public $authorizationChecker; + + /** * @var CountNotificationTask */ public $counter; - + /* * @var TokenStorageInterface */ public $tokenStorage; - + /** - * * @var TranslatorInterface */ public $translator; - - /** - * - * @var AuthorizationCheckerInterface - */ - public $authorizationChecker; - + public function __construct( CountNotificationTask $counter, TokenStorageInterface $tokenStorage, @@ -69,73 +52,76 @@ class UserMenuBuilder implements LocalMenuBuilderInterface $this->translator = $translator; $this->authorizationChecker = $authorizationChecker; } - - public static function getMenuIds(): array - { - return [ 'user' ]; - } - + public function buildMenu($menuId, MenuItem $menu, array $parameters) { - if (FALSE === $this->authorizationChecker->isGranted(TaskVoter::SHOW)) { + if (false === $this->authorizationChecker->isGranted(TaskVoter::SHOW)) { return; } - + $user = $this->tokenStorage->getToken()->getUser(); $ended = $this->counter->countNotificationEnded($user); $warning = $this->counter->countNotificationWarning($user); - - if ($ended > 0) { + + if (0 < $ended) { $this->addItemInMenu( - $menu, - $user, - '%number% tasks over deadline', + $menu, + $user, + '%number% tasks over deadline', 'My tasks over deadline', SingleTaskRepository::DATE_STATUS_ENDED, - $ended, - -15); + $ended, + -15 + ); } - - if ($warning > 0) { + + if (0 < $warning) { $this->addItemInMenu( - $menu, - $user, - '%number% tasks near deadline', - 'My tasks near deadline', + $menu, + $user, + '%number% tasks near deadline', + 'My tasks near deadline', SingleTaskRepository::DATE_STATUS_WARNING, - $warning, - -14); + $warning, + -14 + ); } - - $menu->addChild("My tasks", [ - 'route' => 'chill_task_single_my_tasks' - ]) + + $menu->addChild('My tasks', [ + 'route' => 'chill_task_single_my_tasks', + ]) ->setExtras([ 'order' => -10, - 'icon' => 'tasks' + 'icon' => 'tasks', ]); } - + + public static function getMenuIds(): array + { + return ['user']; + } + protected function addItemInMenu(MenuItem $menu, User $u, $message, $title, $status, $number, $order) { - if ($number > 0) { + if (0 < $number) { $menu->addChild( - $this->translator->transChoice($message, $number), + $this->translator->transChoice($message, $number), [ 'route' => 'chill_task_singletask_list', 'routeParameters' => [ 'user_id' => $u->getId(), 'status' => [ - $status - ], + $status, + ], 'hide_form' => true, - 'title' => $this->translator->trans($title) + 'title' => $this->translator->trans($title), + ], ] - ]) + ) ->setExtras([ - 'order'=> $order, + 'order' => $order, 'icon' => 'exclamation-triangle', - 'entryclass' => 'user_menu__entry--warning-entry' + 'entryclass' => 'user_menu__entry--warning-entry', ]); } } diff --git a/src/Bundle/ChillTaskBundle/Repository/AbstractTaskRepository.php b/src/Bundle/ChillTaskBundle/Repository/AbstractTaskRepository.php index d5c7627c0..04ce82c77 100644 --- a/src/Bundle/ChillTaskBundle/Repository/AbstractTaskRepository.php +++ b/src/Bundle/ChillTaskBundle/Repository/AbstractTaskRepository.php @@ -1,9 +1,16 @@ authorizationHelper = $authorizationHelper; - } - /** * Count the tasks for given parameters. * * The parameters are describe in @see SingleTaskRepository::filterByParameters. * * @see SingleTaskRepository::filterByParameters + * * @param array $params * @param User $currentUser + * * @return int */ - public function countByParameters($params, User $currentUser = null) + public function countByParameters($params, ?User $currentUser = null) { $qb = $this->createQueryBuilder('st') ->select('COUNT(st)'); @@ -61,8 +69,7 @@ class SingleTaskRepository extends EntityRepository return (int) $qb ->getQuery() - ->getSingleScalarResult() - ; + ->getSingleScalarResult(); } /** @@ -80,9 +87,7 @@ class SingleTaskRepository extends EntityRepository * - `types`: string[] an array of task types * * @param type $params - * @param User $currentUser - * @param int $firstResult - * @param int $maxResults + * * @return type */ public function findByParameters($params, User $currentUser, int $firstResult = 0, int $maxResults = 50) @@ -93,68 +98,16 @@ class SingleTaskRepository extends EntityRepository $qb ->setMaxResults($maxResults) - ->setFirstResult($firstResult) - ; + ->setFirstResult($firstResult); return $qb ->getQuery() - ->getResult() - ; + ->getResult(); } - protected function buildQuery(QueryBuilder $qb, $params, User $currentUser = null) + public function setAuthorizationHelper(AuthorizationHelper $authorizationHelper) { - if (NULL !== $currentUser) { - $this->buildACLQuery($qb, $currentUser); - } - - if (\array_key_exists('person', $params) and !empty($params['person'])) { - $qb->andWhere($qb->expr()->eq('st.person', ':person')); - $qb->setParameter('person', $params['person']); - } elseif (\array_key_exists('center', $params)) { - if ($params['center'] instanceof Center) { - $qb->join('st.person', 'person'); - $qb->andWhere($qb->expr()->eq('person.center', ':center')); - $qb->setParameter('center', $params['center']); - } else { - throw new \UnexpectedValueException("params 'center' should be an instance of ".Center::class); - } - } - - if (\array_key_exists('unassigned', $params) and $params['unassigned'] === true) { - if (\array_key_exists('user', $params) and !empty($params['user'])) { - throw new \UnexpectedValueException("You should not require for " - . "unassigned tasks and tasks assigned to some user."); - } - - $qb->andWhere($qb->expr()->isNull('st.assignee')); - } - - if (\array_key_exists('user', $params) and !empty($params['user'])) { - $qb->andWhere($qb->expr()->eq('st.assignee', ':user')); - $qb->setParameter('user', $params['user']); - } - - if (\array_key_exists('scope', $params) and !empty($params['scope'])) { - $qb->andWhere($qb->expr()->eq('st.circle', ':scope')); - $qb->setParameter('scope', $params['scope']); - } - - if (\array_key_exists('types', $params) && $params['types'] !== NULL) { - if (count($params['types']) > 0) { - $qb->andWhere($qb->expr()->in('st.type', ':types')); - $qb->setParameter('types', $params['types']); - } - } - - if (\array_key_exists('date_status', $params) and !empty($params['date_status'])) { - $this->addTypeFilter($qb, $params); - } - - if (\array_key_exists('is_closed', $params)) { - $qb->andWhere($this->buildIsClosed($qb, !$params['is_closed'])); - } - + $this->authorizationHelper = $authorizationHelper; } protected function addTypeFilter(QueryBuilder $qb, $params) @@ -164,15 +117,15 @@ class SingleTaskRepository extends EntityRepository switch ($params['date_status']) { case self::DATE_STATUS_ENDED: $andWhere - ->add($this->buildNowIsAfterEndDate($qb)) - ; + ->add($this->buildNowIsAfterEndDate($qb)); + break; case self::DATE_STATUS_WARNING: $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) - ->add($this->buildNowIsAfterWarningDate($qb)) - ; + ->add($this->buildNowIsAfterWarningDate($qb)); + break; case self::DATE_STATUS_CURRENT: @@ -180,125 +133,174 @@ class SingleTaskRepository extends EntityRepository $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) ->add($this->buildNowIsAfterWarningDate($qb, true)) - ->add($this->buildNowIsAfterStartDate($qb, false)) - ; + ->add($this->buildNowIsAfterStartDate($qb, false)); + break; case self::DATE_STATUS_NOT_STARTED: $andWhere ->add($this->buildNowIsAfterEndDate($qb, true)) ->add($this->buildNowIsAfterWarningDate($qb, true)) - ->add($this->buildNowIsAfterStartDate($qb, true)) - ; + ->add($this->buildNowIsAfterStartDate($qb, true)); } - $qb->setParameter('now', new \DateTime('today'), Type::DATE); + $qb->setParameter('now', new DateTime('today'), Type::DATE); $qb->andWhere($andWhere); } - private function buildNowIsAfterEndDate(QueryBuilder $qb, $negative = false) - { - if ($negative === false) { - return $qb->expr()->andX() - ->add($qb->expr()->isNotNull('st.endDate')) - ->add($qb->expr()->lte('st.endDate', ':now')) - ; - } else { - return $qb->expr()->orX() - ->add( - $qb->expr()->andX() - ->add($qb->expr()->isNotNull('st.endDate')) - ->add($qb->expr()->gt('st.endDate', ':now')) - ) - ->add($qb->expr()->isNull('st.endDate')) - ; - } - } - - private function buildNowIsAfterWarningDate(QueryBuilder $qb, bool $negative = false) - { - if ($negative === false) { - return $qb->expr()->andX() - ->add($qb->expr()->lte( - $qb->expr()->diff('st.endDate', 'st.warningInterval'), ':now' - ) - ); - } else { - return $qb->expr()->orX() - ->add( - $qb->expr()->andX() - ->add($qb->expr()->isNotNull('st.endDate')) - ->add($qb->expr()->isNotNull('st.warningInterval')) - ->add($qb->expr()->gt( - $qb->expr()->diff('st.endDate', 'st.warningInterval'), - ':now' - ) - ) - ) - ->add($qb->expr()->isNull('st.endDate')) - ->add($qb->expr()->isNull('st.warningInterval')) - ; - } - } - - private function buildNowIsAfterStartDate(QueryBuilder $qb, bool $negative = false) - { - if ($negative === false) { - return $qb->expr()->orX() - ->add($qb->expr()->lte('st.startDate', ':now')) - ->add($qb->expr()->isNull('st.startDate')) - ; - } else { - return - $qb->expr()->andX() - ->add($qb->expr()->gt('st.startDate', ':now')) - ->add($qb->expr()->isNotNull('st.startDate')) - ; - } - } - - private function buildIsClosed(QueryBuilder $qb, bool $negative = false) - { - if ($negative === false) { - return $qb->expr()->eq('st.closed', "'TRUE'"); - } else { - return $qb->expr()->eq('st.closed', "'FALSE'"); - } - } - - protected function buildACLQuery(QueryBuilder $qb, User $currentUser) { - if (NULL === $this->authorizationHelper) { - throw new \LogicException("Injecting the authorization helper is " - . "required to run this query. Please use dependency injection " - . "to initialize this repository or use the method " - . "`setAuthorizationHelper`"); + if (null === $this->authorizationHelper) { + throw new LogicException('Injecting the authorization helper is ' + . 'required to run this query. Please use dependency injection ' + . 'to initialize this repository or use the method ' + . '`setAuthorizationHelper`'); } $role = new Role(TaskVoter::SHOW); $qb->join('st.person', 'p'); $centers = $this->authorizationHelper - ->getReachableCenters($currentUser, $role) - ; + ->getReachableCenters($currentUser, $role); $i = 0; $where = $qb->expr()->orX(); - foreach($centers as $center) { + foreach ($centers as $center) { $circles = $this->authorizationHelper ->getReachableCircles($currentUser, $role, $center); $centerWhere = $qb->expr()->andX(); - $centerWhere->add($qb->expr()->eq('p.center', ':center_'.$i)); - $qb->setParameter('center_'.$i, $center); - $centerWhere->add($qb->expr()->in('st.circle', ':circles_'.$i)); - $qb->setParameter('circles_'.$i, $circles); + $centerWhere->add($qb->expr()->eq('p.center', ':center_' . $i)); + $qb->setParameter('center_' . $i, $center); + $centerWhere->add($qb->expr()->in('st.circle', ':circles_' . $i)); + $qb->setParameter('circles_' . $i, $circles); $where->add($centerWhere); - $i ++; + ++$i; } $qb->where($where); } + + protected function buildQuery(QueryBuilder $qb, $params, ?User $currentUser = null) + { + if (null !== $currentUser) { + $this->buildACLQuery($qb, $currentUser); + } + + if (array_key_exists('person', $params) and !empty($params['person'])) { + $qb->andWhere($qb->expr()->eq('st.person', ':person')); + $qb->setParameter('person', $params['person']); + } elseif (array_key_exists('center', $params)) { + if ($params['center'] instanceof Center) { + $qb->join('st.person', 'person'); + $qb->andWhere($qb->expr()->eq('person.center', ':center')); + $qb->setParameter('center', $params['center']); + } else { + throw new UnexpectedValueException("params 'center' should be an instance of " . Center::class); + } + } + + if (array_key_exists('unassigned', $params) and true === $params['unassigned']) { + if (array_key_exists('user', $params) and !empty($params['user'])) { + throw new UnexpectedValueException('You should not require for ' + . 'unassigned tasks and tasks assigned to some user.'); + } + + $qb->andWhere($qb->expr()->isNull('st.assignee')); + } + + if (array_key_exists('user', $params) and !empty($params['user'])) { + $qb->andWhere($qb->expr()->eq('st.assignee', ':user')); + $qb->setParameter('user', $params['user']); + } + + if (array_key_exists('scope', $params) and !empty($params['scope'])) { + $qb->andWhere($qb->expr()->eq('st.circle', ':scope')); + $qb->setParameter('scope', $params['scope']); + } + + if (array_key_exists('types', $params) && null !== $params['types']) { + if (count($params['types']) > 0) { + $qb->andWhere($qb->expr()->in('st.type', ':types')); + $qb->setParameter('types', $params['types']); + } + } + + if (array_key_exists('date_status', $params) and !empty($params['date_status'])) { + $this->addTypeFilter($qb, $params); + } + + if (array_key_exists('is_closed', $params)) { + $qb->andWhere($this->buildIsClosed($qb, !$params['is_closed'])); + } + } + + private function buildIsClosed(QueryBuilder $qb, bool $negative = false) + { + if (false === $negative) { + return $qb->expr()->eq('st.closed', "'TRUE'"); + } + + return $qb->expr()->eq('st.closed', "'FALSE'"); + } + + private function buildNowIsAfterEndDate(QueryBuilder $qb, $negative = false) + { + if (false === $negative) { + return $qb->expr()->andX() + ->add($qb->expr()->isNotNull('st.endDate')) + ->add($qb->expr()->lte('st.endDate', ':now')); + } + + return $qb->expr()->orX() + ->add( + $qb->expr()->andX() + ->add($qb->expr()->isNotNull('st.endDate')) + ->add($qb->expr()->gt('st.endDate', ':now')) + ) + ->add($qb->expr()->isNull('st.endDate')); + } + + private function buildNowIsAfterStartDate(QueryBuilder $qb, bool $negative = false) + { + if (false === $negative) { + return $qb->expr()->orX() + ->add($qb->expr()->lte('st.startDate', ':now')) + ->add($qb->expr()->isNull('st.startDate')); + } + + return + $qb->expr()->andX() + ->add($qb->expr()->gt('st.startDate', ':now')) + ->add($qb->expr()->isNotNull('st.startDate')); + } + + private function buildNowIsAfterWarningDate(QueryBuilder $qb, bool $negative = false) + { + if (false === $negative) { + return $qb->expr()->andX() + ->add( + $qb->expr()->lte( + $qb->expr()->diff('st.endDate', 'st.warningInterval'), + ':now' + ) + ); + } + + return $qb->expr()->orX() + ->add( + $qb->expr()->andX() + ->add($qb->expr()->isNotNull('st.endDate')) + ->add($qb->expr()->isNotNull('st.warningInterval')) + ->add( + $qb->expr()->gt( + $qb->expr()->diff('st.endDate', 'st.warningInterval'), + ':now' + ) + ) + ) + ->add($qb->expr()->isNull('st.endDate')) + ->add($qb->expr()->isNull('st.warningInterval')); + } } diff --git a/src/Bundle/ChillTaskBundle/Security/Authorization/AuthorizationEvent.php b/src/Bundle/ChillTaskBundle/Security/Authorization/AuthorizationEvent.php index 38cda7563..e5109e23f 100644 --- a/src/Bundle/ChillTaskBundle/Security/Authorization/AuthorizationEvent.php +++ b/src/Bundle/ChillTaskBundle/Security/Authorization/AuthorizationEvent.php @@ -1,47 +1,44 @@ - */ class AuthorizationEvent extends Event { + public const VOTE = 'chill_task.vote'; + /** - * @var Chill\TaskBundle\Entity\AbstractTask|\Chill\PersonBundle\Entity\Person|null - */ - protected $subject; - - /** - * * @var string */ protected $attribute; - + + /** + * @var \Chill\PersonBundle\Entity\Person|Chill\TaskBundle\Entity\AbstractTask|null + */ + protected $subject; + /** - * * @var TokenInterface */ protected $token; - + /** - * * @var bool */ protected $vote; - - const VOTE = 'chill_task.vote'; - + public function __construct( - $subject, - $attribute, + $subject, + $attribute, TokenInterface $token ) { $this->subject = $subject; @@ -49,40 +46,40 @@ class AuthorizationEvent extends Event $this->token = $token; } - public function getSubject() - { - return $this->subject; - } - public function getAttribute() { return $this->attribute; } + public function getSubject() + { + return $this->subject; + } + public function getToken(): TokenInterface { return $this->token; } - + public function getVote() { return $this->vote; } - - public function setVote($vote) - { - $this->vote = $vote; - - return $this; - } public function hasVote() { - return $this->vote !== NULL; + return null !== $this->vote; } - + public function removeVote() { - $this->vote = NULL; + $this->vote = null; + } + + public function setVote($vote) + { + $this->vote = $vote; + + return $this; } } diff --git a/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php b/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php index 8b8bce839..404a5c046 100644 --- a/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php +++ b/src/Bundle/ChillTaskBundle/Security/Authorization/TaskVoter.php @@ -1,80 +1,65 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\TaskBundle\Security\Authorization; -use Chill\MainBundle\Security\Authorization\AbstractChillVoter; -use Chill\TaskBundle\Entity\AbstractTask; -use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Chill\PersonBundle\Security\Authorization\PersonVoter; -use Psr\Log\LoggerInterface; -use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Security\Authorization\AbstractChillVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Security\ProvideRoleHierarchyInterface; use Chill\PersonBundle\Entity\Person; -use Symfony\Component\Security\Core\Role\Role; +use Chill\PersonBundle\Security\Authorization\PersonVoter; +use Chill\TaskBundle\Entity\AbstractTask; +use LogicException; +use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Chill\TaskBundle\Security\Authorization\AuthorizationEvent; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Role\Role; -/** - * - * - * @author Julien Fastré - */ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface { - const CREATE = 'CHILL_TASK_TASK_CREATE'; - const UPDATE = 'CHILL_TASK_TASK_UPDATE'; - const SHOW = 'CHILL_TASK_TASK_SHOW'; - const DELETE = 'CHILL_TASK_TASK_DELETE'; + public const CREATE = 'CHILL_TASK_TASK_CREATE'; - const ROLES = [ + public const DELETE = 'CHILL_TASK_TASK_DELETE'; + + public const ROLES = [ self::CREATE, self::UPDATE, self::SHOW, - self::DELETE + self::DELETE, ]; - /** - * - * @var AuthorizationHelper - */ - protected $authorizationHelper; + public const SHOW = 'CHILL_TASK_TASK_SHOW'; + + public const UPDATE = 'CHILL_TASK_TASK_UPDATE'; /** - * * @var AccessDecisionManagerInterface */ protected $accessDecisionManager; /** - * - * @var LoggerInterface + * @var AuthorizationHelper */ - protected $logger; - + protected $authorizationHelper; + /** - * * @var EventDispatcherInterface */ protected $eventDispatcher; + /** + * @var LoggerInterface + */ + protected $logger; + public function __construct( AccessDecisionManagerInterface $accessDecisionManager, AuthorizationHelper $authorizationHelper, @@ -87,74 +72,6 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf $this->logger = $logger; } - public function supports($attribute, $subject) - { - return ($subject instanceof AbstractTask && in_array($attribute, self::ROLES)) - || - ($subject instanceof Person && \in_array($attribute, [ self::CREATE, self::SHOW ])) - || - (NULL === $subject && $attribute === self::SHOW ) - ; - } - - /** - * - * @param string $attribute - * @param AbstractTask $subject - * @param TokenInterface $token - * @return boolean - */ - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) - { - $this->logger->debug(sprintf("Voting from %s class", self::class)); - - if (!$token->getUser() instanceof User) { - return false; - } - - $event = new AuthorizationEvent($subject, $attribute, $token); - - $this->eventDispatcher->dispatch(AuthorizationEvent::VOTE, $event); - - if ($event->hasVote()) { - - $this->logger->debug("The TaskVoter is overriding by " - .AuthorizationEvent::VOTE, [ - 'vote' => $event->getVote(), - 'task_id' => $subject->getId() - ]); - - return $event->getVote(); - } - - if ($subject instanceof AbstractTask) { - if ($subject->getPerson() === null) { - throw new \LogicException("You should associate a person with task " - . "in order to check autorizations"); - } - - $person = $subject->getPerson(); - } elseif ($subject instanceof Person) { - $person = $subject; - } else { - // subject is null. We check that at least one center is reachable - $centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute)); - - return count($centers) > 0; - } - - if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { - - return false; - } - - return $this->authorizationHelper->userHasAccess( - $token->getUser(), - $subject, - $attribute - ); - } - public function getRoles() { return self::ROLES; @@ -163,7 +80,7 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf public function getRolesWithHierarchy(): array { return [ - 'Task' => self::ROLES + 'Task' => self::ROLES, ]; } @@ -172,4 +89,65 @@ class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterf return []; } + public function supports($attribute, $subject) + { + return ($subject instanceof AbstractTask && in_array($attribute, self::ROLES)) + || ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SHOW])) + || (null === $subject && self::SHOW === $attribute); + } + + /** + * @param string $attribute + * @param AbstractTask $subject + * + * @return bool + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $this->logger->debug(sprintf('Voting from %s class', self::class)); + + if (!$token->getUser() instanceof User) { + return false; + } + + $event = new AuthorizationEvent($subject, $attribute, $token); + + $this->eventDispatcher->dispatch(AuthorizationEvent::VOTE, $event); + + if ($event->hasVote()) { + $this->logger->debug('The TaskVoter is overriding by ' + . AuthorizationEvent::VOTE, [ + 'vote' => $event->getVote(), + 'task_id' => $subject->getId(), + ]); + + return $event->getVote(); + } + + if ($subject instanceof AbstractTask) { + if ($subject->getPerson() === null) { + throw new LogicException('You should associate a person with task ' + . 'in order to check autorizations'); + } + + $person = $subject->getPerson(); + } elseif ($subject instanceof Person) { + $person = $subject; + } else { + // subject is null. We check that at least one center is reachable + $centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute)); + + return count($centers) > 0; + } + + if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) { + return false; + } + + return $this->authorizationHelper->userHasAccess( + $token->getUser(), + $subject, + $attribute + ); + } } diff --git a/src/Bundle/ChillTaskBundle/Templating/TaskTwigExtension.php b/src/Bundle/ChillTaskBundle/Templating/TaskTwigExtension.php index e79cdcda2..98c41edf3 100644 --- a/src/Bundle/ChillTaskBundle/Templating/TaskTwigExtension.php +++ b/src/Bundle/ChillTaskBundle/Templating/TaskTwigExtension.php @@ -1,58 +1,43 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Templating; - -use Twig\Extension\AbstractExtension; -use Twig\TwigFunction; -use Chill\TaskBundle\Entity\AbstractTask; -use Chill\TaskBundle\Workflow\TaskWorkflowManager; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Templating; + +use Chill\TaskBundle\Entity\AbstractTask; +use Chill\TaskBundle\Workflow\TaskWorkflowManager; +use Twig\Extension\AbstractExtension; +use Twig\TwigFunction; + class TaskTwigExtension extends AbstractExtension { /** - * * @var TaskWorkflowManager */ protected $taskWorkflowManager; - + public function __construct(TaskWorkflowManager $taskWorkflowManager) { $this->taskWorkflowManager = $taskWorkflowManager; } - public function getFunctions() { return [ - new TwigFunction('task_workflow_metadata', [ $this, 'getWorkflowMetadata' ] ) + new TwigFunction('task_workflow_metadata', [$this, 'getWorkflowMetadata']), ]; } - + public function getWorkflowMetadata( - AbstractTask $task, - string $key, - $metadataSubject = null, - string $name = null + AbstractTask $task, + string $key, + $metadataSubject = null, + ?string $name = null ) { return $this->taskWorkflowManager->getWorkflowMetadata($task, $key, $metadataSubject, $name); } diff --git a/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.php b/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.php index e53b85fbe..f378e0c4b 100644 --- a/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.php +++ b/src/Bundle/ChillTaskBundle/Templating/UI/CountNotificationTask.php @@ -1,50 +1,37 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Templating\UI; - -use Chill\MainBundle\Templating\UI\NotificationCounterInterface; -use Symfony\Component\Security\Core\User\UserInterface; -use Chill\MainBundle\Entity\User; -use Chill\TaskBundle\Repository\SingleTaskRepository; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Workflow\Event\Event; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Templating\UI; + +use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Templating\UI\NotificationCounterInterface; +use Chill\TaskBundle\Repository\SingleTaskRepository; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Workflow\Event\Event; + +use function array_merge; + class CountNotificationTask implements NotificationCounterInterface { + public const CACHE_KEY = 'chill_task.count_notifications.user.%d.%s'; + /** - * - * @var SingleTaskRepository - */ - protected $singleTaskRepository; - - /** - * * @var CacheItempPoolInterface */ protected $cachePool; - - const CACHE_KEY = 'chill_task.count_notifications.user.%d.%s'; - + + /** + * @var SingleTaskRepository + */ + protected $singleTaskRepository; + public function __construct( SingleTaskRepository $singleTaskRepository, CacheItemPoolInterface $cachePool @@ -52,66 +39,41 @@ class CountNotificationTask implements NotificationCounterInterface $this->singleTaskRepository = $singleTaskRepository; $this->cachePool = $cachePool; } - - public function countNotification(UserInterface $u): int - { - return - $this->countNotificationEnded($u) - + $this->countNotificationWarning($u); - } - - public function countNotificationEnded(UserInterface $u): int - { - return $this->_countNotification($u, SingleTaskRepository::DATE_STATUS_ENDED); - } - - public function countNotificationWarning(UserInterface $u): int - { - return $this->_countNotification($u, SingleTaskRepository::DATE_STATUS_WARNING); - } - - protected function _countNotification(UserInterface $u, $status) - { - if (!$u instanceof User) { - return 0; - } - - $sumCache = $this->cachePool->getItem($this->getCacheKey($u, $status)); - - if ($sumCache->isHit()) { - return $sumCache->get(); - } - - $params = [ - 'user' => $u, - 'is_closed' => false - ]; - - $sum = $this->singleTaskRepository->countByParameters( - \array_merge($params, [ 'date_status' => $status ]) - ); - - $sumCache->set($sum); - $this->cachePool->save($sumCache); - - return $sum; - } - + public function addNotification(UserInterface $u): int { return $this->countNotification($u); } - + + public function countNotification(UserInterface $u): int + { + return + $this->countNotificationEnded($u) + + $this->countNotificationWarning($u); + } + + public function countNotificationEnded(UserInterface $u): int + { + return $this->_countNotification($u, SingleTaskRepository::DATE_STATUS_ENDED); + } + + public function countNotificationWarning(UserInterface $u): int + { + return $this->_countNotification($u, SingleTaskRepository::DATE_STATUS_WARNING); + } + public function resetCacheOnNewStates(Event $e) { /* @var $task \Chill\TaskBundle\Entity\SingleTask */ $task = $e->getSubject(); - - if (NULL !== $task->getAssignee()) { - foreach ([ - SingleTaskRepository::DATE_STATUS_ENDED, - SingleTaskRepository::DATE_STATUS_WARNING - ] as $status) { + + if (null !== $task->getAssignee()) { + foreach ( + [ + SingleTaskRepository::DATE_STATUS_ENDED, + SingleTaskRepository::DATE_STATUS_WARNING, + ] as $status + ) { $key = $this->getCacheKey($task->getAssignee(), $status); $sumCache = $this->cachePool->getItem($key); @@ -121,9 +83,36 @@ class CountNotificationTask implements NotificationCounterInterface } } } - + + protected function _countNotification(UserInterface $u, $status) + { + if (!$u instanceof User) { + return 0; + } + + $sumCache = $this->cachePool->getItem($this->getCacheKey($u, $status)); + + if ($sumCache->isHit()) { + return $sumCache->get(); + } + + $params = [ + 'user' => $u, + 'is_closed' => false, + ]; + + $sum = $this->singleTaskRepository->countByParameters( + array_merge($params, ['date_status' => $status]) + ); + + $sumCache->set($sum); + $this->cachePool->save($sumCache); + + return $sum; + } + private function getCacheKey(User $u, $status) { - return sprintf(self::CACHE_KEY, $u->getId(), $status); + return sprintf(self::CACHE_KEY, $u->getId(), $status); } } diff --git a/src/Bundle/ChillTaskBundle/Tests/Controller/SingleTaskControllerTest.php b/src/Bundle/ChillTaskBundle/Tests/Controller/SingleTaskControllerTest.php index d7337029d..19a2e9cd7 100644 --- a/src/Bundle/ChillTaskBundle/Tests/Controller/SingleTaskControllerTest.php +++ b/src/Bundle/ChillTaskBundle/Tests/Controller/SingleTaskControllerTest.php @@ -1,102 +1,114 @@ faker = Faker\Factory::create('fr'); } - + + public function testNew() + { + $client = static::createClient( + [], + TestHelper::getAuthenticatedClientOptions() + ); + $person = $this->getRandomPerson('Center A'); + + $crawler = $client->request('GET', '/fr/task/single-task/new', [ + 'person_id' => $person->getId(), + ]); + var_dump($crawler->text()); + + $this->assertTrue($client->getResponse()->isSuccessful()); + + $form = $crawler->selectButton('Envoi')->form(); + + $title = $this->faker->sentence; + $circles = $form->get('circle') + ->availableOptionsValues(); + + $client->submit($form, [ + 'title' => $title, + 'circle' => $circles[array_rand($circles)], + ]); + + $this->assertTrue($client->getResponse()->isRedirect(sprintf( + '/fr/task/task/list/%d', + $person->getId() + ))); + + $crawler = $client->followRedirect(); + + $this->assertContains( + $title, + $crawler->text(), + 'Assert that newly created task title is shown in list page' + ); + } + /** - * + * @param mixed $centerName + * * @return \Chill\PersonBundle\Entity\Person */ protected function getRandomPerson($centerName) { $em = self::$kernel ->getContainer() - ->get('doctrine.orm.entity_manager') - ; - + ->get('doctrine.orm.entity_manager'); + $centers = $em ->getRepository(Center::class) ->findAll(); - - $center = \array_filter( - $centers, - function(Center $c) use ($centerName) { - return $centerName === $c->getName(); - })[0]; - + + $center = array_filter( + $centers, + function (Center $c) use ($centerName) { + return $c->getName() === $centerName; + } + )[0]; + $ids = $em - ->createQuery('SELECT p.id FROM ChillPersonBundle:Person p ' + ->createQuery( + 'SELECT p.id FROM ChillPersonBundle:Person p ' . 'WHERE p.center = :center' - ) + ) ->setParameter('center', $center) - ->getResult() - ; - - $id = $ids[\array_rand($ids)]; - + ->getResult(); + + $id = $ids[array_rand($ids)]; + return self::$kernel ->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository(\Chill\PersonBundle\Entity\Person::class) - ->find($id) - ; + ->find($id); } - - public function testNew() - { - $client = static::createClient( - array(), - TestHelper::getAuthenticatedClientOptions() - ); - $person = $this->getRandomPerson('Center A'); - - $crawler = $client->request('GET', '/fr/task/single-task/new', [ - 'person_id' => $person->getId() - ]); - var_dump($crawler->text()); - - $this->assertTrue($client->getResponse()->isSuccessful()); - - - - $form = $crawler->selectButton('Envoi')->form(); - - $title = $this->faker->sentence; - $circles = $form->get('circle') - ->availableOptionsValues() - ; - - $client->submit($form, [ - 'title' => $title, - 'circle' => $circles[\array_rand($circles)] - ]); - - $this->assertTrue($client->getResponse()->isRedirect(sprintf( - '/fr/task/task/list/%d', $person->getId()))); - - $crawler = $client->followRedirect(); - - $this->assertContains($title, $crawler->text(), - "Assert that newly created task title is shown in list page") - ; - } - } diff --git a/src/Bundle/ChillTaskBundle/Tests/Controller/TaskControllerTest.php b/src/Bundle/ChillTaskBundle/Tests/Controller/TaskControllerTest.php index 18b980329..67c775fc2 100644 --- a/src/Bundle/ChillTaskBundle/Tests/Controller/TaskControllerTest.php +++ b/src/Bundle/ChillTaskBundle/Tests/Controller/TaskControllerTest.php @@ -1,9 +1,20 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Timeline; use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManagerInterface; -use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; use Chill\TaskBundle\Entity\SingleTask; +use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; +use Doctrine\ORM\EntityManagerInterface; +use LogicException; use Symfony\Component\Workflow\Registry; use Symfony\Component\Workflow\Workflow; -/** - * - * - * @author Julien Fastré - */ +use function array_combine; +use function array_map; + class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderInterface { + public const TYPE = 'chill_task.transition'; + /** - * * @var EntityManagerInterface */ protected $em; /** - * * @var Registry */ protected $registry; - const TYPE = 'chill_task.transition'; - public function __construct(EntityManagerInterface $em, Registry $registry) { $this->em = $em; @@ -53,8 +42,8 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn public function fetchQuery($context, $args) { - if ($context !== 'task') { - throw new \LogicException(sprintf('%s is not able ' + if ('task' !== $context) { + throw new LogicException(sprintf('%s is not able ' . 'to render context %s', self::class, $context)); } @@ -67,32 +56,34 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn 'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')), 'type' => self::TYPE, 'date' => $metadata->getColumnName('datetime'), - 'FROM' => sprintf('%s JOIN %s ON %s = %s', + 'FROM' => sprintf( + '%s JOIN %s ON %s = %s', sprintf('%s.%s', $metadata->getSchemaName(), $metadata->getTableName()), sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()), $metadata->getAssociationMapping('task')['joinColumns'][0]['name'], sprintf('%s.%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName(), $singleTaskMetadata->getColumnName('id')) - ), - 'WHERE' => sprintf('%s.%s = %d', + ), + 'WHERE' => sprintf( + '%s.%s = %d', sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()), $singleTaskMetadata->getColumnName('id'), $args['task']->getId() - ) + ), ]; - } public function getEntities(array $ids) { $events = $this->em ->getRepository(SingleTaskPlaceEvent::class) - ->findBy([ 'id' => $ids ]) - ; + ->findBy(['id' => $ids]); - return \array_combine( - \array_map(function($e) { return $e->getId(); }, $events ), + return array_combine( + array_map(function ($e) { + return $e->getId(); + }, $events), $events - ); + ); } public function getEntityTemplate($entity, $context, array $args) @@ -101,21 +92,25 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn $workflow = $this->registry->get($entity->getTask(), $entity->getData()['workflow']); $transition = $this->getTransitionByName($entity->getTransition(), $workflow); } - + return [ 'template' => 'ChillTaskBundle:Timeline:single_task_transition_task_context.html.twig', 'template_data' => [ 'task' => $args['task'], 'event' => $entity, - 'transition' => $transition ?? null - ] + 'transition' => $transition ?? null, + ], ]; } + public function supportsType($type): bool + { + return self::TYPE === $type; + } + /** - * * @param string $name - * @param Workflow $workflow + * * @return \Symfony\Component\Workflow\Transition */ protected function getTransitionByName($name, Workflow $workflow) @@ -126,9 +121,4 @@ class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderIn } } } - - public function supportsType($type): bool - { - return $type === self::TYPE; - } } diff --git a/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php b/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php index db099a3e1..d31c7c942 100644 --- a/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php +++ b/src/Bundle/ChillTaskBundle/Timeline/TaskLifeCycleEventTimelineProvider.php @@ -1,68 +1,56 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Timeline; - -use Chill\MainBundle\Timeline\TimelineProviderInterface; -use Doctrine\ORM\EntityManagerInterface; -use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; -use Chill\TaskBundle\Entity\SingleTask; -use Symfony\Component\Workflow\Registry; -use Symfony\Component\Workflow\Workflow; -use Chill\MainBundle\Security\Authorization\AuthorizationHelper; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Chill\ActivityBundle\Security\Authorization\ActivityVoter; -use Symfony\Component\Security\Core\Role\Role; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Timeline; + +use Chill\ActivityBundle\Security\Authorization\ActivityVoter; +use Chill\MainBundle\Security\Authorization\AuthorizationHelper; +use Chill\MainBundle\Timeline\TimelineProviderInterface; +use Chill\TaskBundle\Entity\SingleTask; +use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent; +use Doctrine\ORM\EntityManagerInterface; +use LogicException; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Workflow\Registry; +use Symfony\Component\Workflow\Workflow; + +use function array_combine; +use function array_map; +use function implode; + class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface { + public const TYPE = 'chill_task.transition'; + /** - * - * @var EntityManagerInterface - */ - protected $em; - - /** - * - * @var Registry - */ - protected $registry; - - /** - * * @var AuthorizationHelper */ protected $authorizationHelper; - + + /** + * @var EntityManagerInterface + */ + protected $em; + + /** + * @var Registry + */ + protected $registry; + /** - * * @var TokenStorageInterface */ protected $tokenStorage; - - const TYPE = 'chill_task.transition'; - + public function __construct( - EntityManagerInterface $em, + EntityManagerInterface $em, Registry $registry, AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage @@ -75,91 +63,103 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface public function fetchQuery($context, $args) { - if ($context !== 'person') { - throw new \LogicException(sprintf('%s is not able ' + if ('person' !== $context) { + throw new LogicException(sprintf('%s is not able ' . 'to render context %s', self::class, $context)); } - + $metadata = $this->em ->getClassMetadata(SingleTaskPlaceEvent::class); $singleTaskMetadata = $this->em ->getClassMetadata(SingleTask::class); $user = $this->tokenStorage->getToken()->getUser(); $circles = $this->authorizationHelper->getReachableCircles( - $user, new Role(ActivityVoter::SEE_DETAILS), $args['person']->getCenter()); - - + $user, + new Role(ActivityVoter::SEE_DETAILS), + $args['person']->getCenter() + ); + if (count($circles) > 0) { - $circlesId = \array_map(function($c) { return $c->getId(); }, $circles); - $circleRestriction = sprintf('%s.%s.%s IN (%s)', + $circlesId = array_map(function ($c) { + return $c->getId(); + }, $circles); + $circleRestriction = sprintf( + '%s.%s.%s IN (%s)', $singleTaskMetadata->getSchemaName(), // chill_task schema $singleTaskMetadata->getTableName(), // single_task table name $singleTaskMetadata->getAssociationMapping('circle')['joinColumns'][0]['name'], - \implode(', ', $circlesId) - ); + implode(', ', $circlesId) + ); } else { $circleRestriction = 'FALSE = TRUE'; } - - + return [ 'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')), 'type' => self::TYPE, 'date' => $metadata->getColumnName('datetime'), - 'FROM' => sprintf('%s JOIN %s ON %s = %s', + 'FROM' => sprintf( + '%s JOIN %s ON %s = %s', sprintf('%s.%s', $metadata->getSchemaName(), $metadata->getTableName()), sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()), $metadata->getAssociationMapping('task')['joinColumns'][0]['name'], sprintf('%s.%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName(), $singleTaskMetadata->getColumnName('id')) - ), - 'WHERE' => sprintf('%s.%s = %d and %s', + ), + 'WHERE' => sprintf( + '%s.%s = %d and %s', sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()), $singleTaskMetadata->getAssociationMapping('person')['joinColumns'][0]['name'], $args['person']->getId(), $circleRestriction - ) + ), ]; - } - - public function getEntities(array $ids) + } + + public function getEntities(array $ids) { $events = $this->em ->getRepository(SingleTaskPlaceEvent::class) - ->findBy([ 'id' => $ids ]) - ; - - return \array_combine( - \array_map(function($e) { return $e->getId(); }, $events ), + ->findBy(['id' => $ids]); + + return array_combine( + array_map(function ($e) { + return $e->getId(); + }, $events), $events - ); - } - + ); + } + public function getEntityTemplate($entity, $context, array $args) { - $workflow = $this->registry->get($entity->getTask(), + $workflow = $this->registry->get( + $entity->getTask(), (isset($entity->getData()['workflow'])) ? $entity->getData()['workflow'] : null ); // sf4 check: prevent error message: // `Notice: Undefined property: Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent::$getData` // * fix syntax error on $entity->getData['workflow'] // * return null if not set - + $transition = $this->getTransitionByName($entity->getTransition(), $workflow); - + return [ 'template' => 'ChillTaskBundle:Timeline:single_task_transition_person_context.html.twig', - 'template_data' => [ + 'template_data' => [ 'person' => $args['person'], 'event' => $entity, - 'transition' => $transition - ] + 'transition' => $transition, + ], ]; - } - + } + + public function supportsType($type): bool + { + return self::TYPE === $type; + } + /** - * * @param string $name - * @param Workflow $workflow + * * @return \Symfony\Component\Workflow\Transition */ protected function getTransitionByName($name, Workflow $workflow) @@ -170,9 +170,4 @@ class TaskLifeCycleEventTimelineProvider implements TimelineProviderInterface } } } - - public function supportsType($type): bool - { - return $type === self::TYPE; - } } diff --git a/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php b/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php index 64b753875..a10cc796a 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php +++ b/src/Bundle/ChillTaskBundle/Workflow/Definition/DefaultTaskDefinition.php @@ -1,67 +1,53 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Workflow\Definition; use Chill\TaskBundle\Entity\AbstractTask; use Chill\TaskBundle\Entity\SingleTask; +use LogicException; use Symfony\Component\Workflow\Transition; -/** - * - * - * @author Julien Fastré - */ +use function array_key_exists; +use function array_slice; +use function explode; +use function implode; + class DefaultTaskDefinition implements \Chill\TaskBundle\Workflow\TaskWorkflowDefinition { - const TRANSITION_METADATA = [ + public const DEFINITION_METADATA = [ + 'name' => 'Default task', + ]; + + public const TRANSITION_METADATA = [ 'close' => [ 'verb' => 'close', 'class' => 'sc-button bt-task-label bt-task-close', 'sentence' => '%user% has closed the task', 'sentence_confirmation' => 'Are you sure you want to close this task ?', - 'apply_transition_submit_label' => 'Close_verb' + 'apply_transition_submit_label' => 'Close_verb', ], 'cancel' => [ 'verb' => 'cancel', 'class' => 'sc-button bt-task-label bt-task-cancel', 'sentence' => '%user% has canceled the task', 'sentence_confirmation' => 'Are you sure you want to cancel this task ?', - 'apply_transition_submit_label' => 'Set this task to cancel state' + 'apply_transition_submit_label' => 'Set this task to cancel state', ], 'start' => [ 'verb' => 'start', 'class' => 'sc-button bt-task-label bt-task-start', 'sentence' => '%user% has started the task', 'sentence_confirmation' => 'Are you sure you want to start this task ?', - 'apply_transition_submit_label' => 'Start_verb' - ] + 'apply_transition_submit_label' => 'Start_verb', + ], ]; - - const DEFINITION_METADATA = [ - 'name' => 'Default task' - ]; - - public function supports(AbstractTask $task) - { - - return $task instanceof SingleTask - && $task->getType() === 'task_default'; - } public static function getAssociatedWorkflowName() { @@ -73,38 +59,46 @@ class DefaultTaskDefinition implements \Chill\TaskBundle\Workflow\TaskWorkflowDe string $key, $metadataSubject = null ) { - $keys = \explode('.', $key); + $keys = explode('.', $key); - switch($keys[0]) { + switch ($keys[0]) { case 'transition': if (!$metadataSubject instanceof Transition) { - throw new \LogicException("You must give a transition as metadatasubject"); + throw new LogicException('You must give a transition as metadatasubject'); } - return $this->getTransitionMetadata(\implode('.', \array_slice($keys, 1)), $metadataSubject); + return $this->getTransitionMetadata(implode('.', array_slice($keys, 1)), $metadataSubject); + case 'definition': return self::DEFINITION_METADATA[$keys[1]] ?? $key; + default: return $key; } } + public function isClosed(AbstractTask $task) + { + return array_key_exists('closed', $task->getCurrentStates()) + || array_key_exists('canceled', $task->getCurrentStates()); + } + + public function supports(AbstractTask $task) + { + return $task instanceof SingleTask + && $task->getType() === 'task_default'; + } + protected function getTransitionMetadata($key, Transition $transition) { - if (!\array_key_exists($transition->getName(), self::TRANSITION_METADATA)) { + if (!array_key_exists($transition->getName(), self::TRANSITION_METADATA)) { return $key; } - if (!\array_key_exists($key, self::TRANSITION_METADATA[$transition->getName()])) { + if (!array_key_exists($key, self::TRANSITION_METADATA[$transition->getName()])) { return $key; } return self::TRANSITION_METADATA[$transition->getName()][$key]; } - - public function isClosed(AbstractTask $task) - { - return \array_key_exists('closed', $task->getCurrentStates()) - || \array_key_exists('canceled', $task->getCurrentStates()); - } } diff --git a/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php b/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php index e4ceff327..2e3145e9b 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php +++ b/src/Bundle/ChillTaskBundle/Workflow/Event/DefaultTaskGuardEvent.php @@ -1,59 +1,49 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Workflow\Event; - -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Workflow\Event\GuardEvent; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Chill\TaskBundle\Security\Authorization\TaskVoter; /** - * + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Workflow\Event; + +use Chill\TaskBundle\Security\Authorization\TaskVoter; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Workflow\Event\GuardEvent; + class DefaultTaskGuardEvent implements EventSubscriberInterface { - public static function getSubscribedEvents(): array - { - return [ - 'workflow.task_default.guard' => [ - 'checkACL' - ] - ]; - } - /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + public function __construct(AuthorizationCheckerInterface $authorizationChecker) { $this->authorizationChecker = $authorizationChecker; } - + public function checkACL(GuardEvent $event) { - if (FALSE === $this->authorizationChecker->isGranted(TaskVoter::UPDATE, - $event->getSubject())) { + if ( + false === $this->authorizationChecker->isGranted( + TaskVoter::UPDATE, + $event->getSubject() + ) + ) { $event->setBlocked(true); } } + + public static function getSubscribedEvents(): array + { + return [ + 'workflow.task_default.guard' => [ + 'checkACL', + ], + ]; + } } diff --git a/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowDefinition.php b/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowDefinition.php index d49591a64..95445ba5e 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowDefinition.php +++ b/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowDefinition.php @@ -1,27 +1,14 @@ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\TaskBundle\Workflow; /** + * Chill is a software for social workers * - * @author Julien Fastré + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + +namespace Chill\TaskBundle\Workflow; + interface TaskWorkflowDefinition { - } diff --git a/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php b/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php index 13be91bd3..076fc352c 100644 --- a/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php +++ b/src/Bundle/ChillTaskBundle/Workflow/TaskWorkflowManager.php @@ -1,93 +1,85 @@ + +/** + * Chill is a software for social workers * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\TaskBundle\Workflow; use Chill\TaskBundle\Entity\AbstractTask; +use LogicException; +use Symfony\Component\Workflow\Event\Event; use Symfony\Component\Workflow\SupportStrategy\WorkflowSupportStrategyInterface; use Symfony\Component\Workflow\WorkflowInterface; -use Symfony\Component\Workflow\Event\Event; -/** - * - * - * @author Julien Fastré - */ +use function sprintf; + class TaskWorkflowManager implements WorkflowSupportStrategyInterface { /** - * * @var TaskWorkflowDefinition[] */ - protected $definitions = array(); - - public function addDefinition(TaskWorkflowDefinition $definition) { + protected $definitions = []; + + public function addDefinition(TaskWorkflowDefinition $definition) + { $this->definitions[] = $definition; } - + /** - * - * @param AbstractTask $task + * @throws LogicException + * * @return TaskWorkflowDefinition - * @throws \LogicException */ public function getTaskWorkflowDefinition(AbstractTask $task) { - $definitions = array(); - - foreach($this->definitions as $tested) { + $definitions = []; + + foreach ($this->definitions as $tested) { if ($tested->supports($task)) { $definitions[] = $tested; } } - + $count = count($definitions); - if ($count > 1) { - throw new \LogicException("More than one TaskWorkflowDefinition supports " - . "this task. This should not happens."); - } elseif ($count === 0) { - throw new \LogicException(\sprintf("No taskWorkflowDefinition supports this task type: %s (task id: %s).", $task->getType(), $task->getId())); + + if (1 < $count) { + throw new LogicException('More than one TaskWorkflowDefinition supports ' + . 'this task. This should not happens.'); } - + + if (0 === $count) { + throw new LogicException(sprintf('No taskWorkflowDefinition supports this task type: %s (task id: %s).', $task->getType(), $task->getId())); + } + return $definitions[0]; } - + + public function getWorkflowMetadata(AbstractTask $task, string $key, $metadataSubject = null, ?string $name = null) + { + return $this->getTaskWorkflowDefinition($task) + ->getWorkflowMetadata($task, $key, $metadataSubject); + } + + public function onTaskStateEntered(Event $e) + { + $task = $e->getSubject(); + + $definition = $this->getTaskWorkflowDefinition($task); + + $task->setClosed($definition->isClosed($task)); + } + public function supports(WorkflowInterface $workflow, $subject): bool { if (!$subject instanceof AbstractTask) { return false; } - + return $workflow->getName() === $this ->getTaskWorkflowDefinition($subject)->getAssociatedWorkflowName(); } - - public function getWorkflowMetadata(AbstractTask $task, string $key, $metadataSubject = null, string $name = null) - { - return $this->getTaskWorkflowDefinition($task) - ->getWorkflowMetadata($task, $key, $metadataSubject); - } - - public function onTaskStateEntered(Event $e) - { - $task = $e->getSubject(); - - $definition = $this->getTaskWorkflowDefinition($task); - - $task->setClosed($definition->isClosed($task)); - } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20180413135614.php b/src/Bundle/ChillTaskBundle/migrations/Version20180413135614.php index 4be2ada22..e6519bd34 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20180413135614.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20180413135614.php @@ -1,18 +1,29 @@ abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SCHEMA chill_task CASCADE'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -27,17 +38,5 @@ class Version20180413135614 extends AbstractMigration $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D859EC7D60 FOREIGN KEY (assignee_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D8217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D870EE2FF6 FOREIGN KEY (circle_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP SCHEMA chill_task CASCADE'); - } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20180413201023.php b/src/Bundle/ChillTaskBundle/migrations/Version20180413201023.php index e04d9ba04..a5e23d033 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20180413201023.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20180413201023.php @@ -1,18 +1,33 @@ abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_task.single_task DROP CONSTRAINT FK_194CB3D840868C31'); + $this->addSql('DROP SEQUENCE chill_task.recurring_task_id_seq CASCADE'); + + $this->addSql('DROP TABLE chill_task.recurring_task'); + $this->addSql('ALTER TABLE chill_task.single_task DROP recurringTask_id'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -30,20 +45,5 @@ class Version20180413201023 extends AbstractMigration $this->addSql('ALTER TABLE chill_task.single_task ADD recurringTask_id INT DEFAULT NULL'); $this->addSql('ALTER TABLE chill_task.single_task ADD CONSTRAINT FK_194CB3D840868C31 FOREIGN KEY (recurringTask_id) REFERENCES chill_task.recurring_task (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_194CB3D840868C31 ON chill_task.single_task (recurringTask_id)'); - - } - - /** - * @param Schema $schema - */ - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_task.single_task DROP CONSTRAINT FK_194CB3D840868C31'); - $this->addSql('DROP SEQUENCE chill_task.recurring_task_id_seq CASCADE'); - - $this->addSql('DROP TABLE chill_task.recurring_task'); - $this->addSql('ALTER TABLE chill_task.single_task DROP recurringTask_id'); } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20180426093011.php b/src/Bundle/ChillTaskBundle/migrations/Version20180426093011.php index b0030bd8a..3a38c78ba 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20180426093011.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20180426093011.php @@ -1,23 +1,24 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_task.single_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL'); - $this->addSql('ALTER TABLE chill_task.recurring_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL'); - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -25,4 +26,12 @@ class Version20180426093011 extends AbstractMigration $this->addSql('ALTER TABLE chill_task.recurring_task DROP closed'); $this->addSql('ALTER TABLE chill_task.single_task DROP closed'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_task.single_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL'); + $this->addSql('ALTER TABLE chill_task.recurring_task ADD closed BOOLEAN DEFAULT \'false\' NOT NULL'); + } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20180502194119.php b/src/Bundle/ChillTaskBundle/migrations/Version20180502194119.php index c62c81744..517896cd7 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20180502194119.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20180502194119.php @@ -1,15 +1,32 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SEQUENCE chill_task.single_task_place_event_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_task.single_task_place_event'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -22,13 +39,4 @@ class Version20180502194119 extends AbstractMigration $this->addSql('ALTER TABLE chill_task.single_task_place_event ADD CONSTRAINT FK_D459EBEEF675F31B FOREIGN KEY (author_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_task.single_task_place_event ADD CONSTRAINT FK_D459EBEE8DB60186 FOREIGN KEY (task_id) REFERENCES chill_task.single_task (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP SEQUENCE chill_task.single_task_place_event_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_task.single_task_place_event'); - - } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20181113161925.php b/src/Bundle/ChillTaskBundle/migrations/Version20181113161925.php index 99a2bbb9f..8d934c0de 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20181113161925.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20181113161925.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP INDEX transition_task_date'); + $this->addSql('DROP INDEX transition_task'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -17,13 +34,4 @@ final class Version20181113161925 extends AbstractMigration $this->addSql('CREATE INDEX transition_task_date ON chill_task.single_task_place_event (task_id, transition, datetime)'); $this->addSql('CREATE INDEX transition_task ON chill_task.single_task_place_event (task_id, transition)'); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP INDEX transition_task_date'); - $this->addSql('DROP INDEX transition_task'); - - } } diff --git a/src/Bundle/ChillTaskBundle/migrations/Version20181113164108.php b/src/Bundle/ChillTaskBundle/migrations/Version20181113164108.php index 68de67114..9d5a9bdcb 100644 --- a/src/Bundle/ChillTaskBundle/migrations/Version20181113164108.php +++ b/src/Bundle/ChillTaskBundle/migrations/Version20181113164108.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('CREATE INDEX by_type ON chill_task.single_task (type)'); - $this->addSql('CREATE INDEX by_current_state ON chill_task.single_task USING GIN (current_states)'); - } - public function down(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -25,4 +26,12 @@ final class Version20181113164108 extends AbstractMigration $this->addSql('DROP INDEX by_type'); $this->addSql('DROP INDEX by_current_state'); } + + public function up(Schema $schema): void + { + $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('CREATE INDEX by_type ON chill_task.single_task (type)'); + $this->addSql('CREATE INDEX by_current_state ON chill_task.single_task USING GIN (current_states)'); + } } diff --git a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php index ba184292a..452891fc0 100644 --- a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php +++ b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php @@ -1,9 +1,16 @@ addCompilerPass(new ThirdPartyTypeCompilerPass()); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php index 59a56af28..eec556b54 100644 --- a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php +++ b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php @@ -1,48 +1,55 @@ paginatorFactory = $paginatorFactory; } - /** * @Route("/index", name="chill_3party_3party_index") */ @@ -60,28 +66,28 @@ class ThirdPartyController extends Controller $this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW); $repository = $this->getDoctrine()->getManager() ->getRepository(ThirdParty::class); - + $centers = $this->authorizationHelper ->getReachableCenters( - $this->getUser(), + $this->getUser(), new Role(ThirdPartyVoter::SHOW) - ); - + ); + $nbThirdParties = $repository->countByMemberOfCenters($centers); $pagination = $this->paginatorFactory->create($nbThirdParties); - + $pagination->setItemsPerPage(20); - + $thirdParties = $repository->findByMemberOfCenters( $centers, $pagination->getCurrentPage()->getFirstItemNumber(), $pagination->getItemsPerPage() ); - - return $this->render('ChillThirdPartyBundle:ThirdParty:index.html.twig', array( + + return $this->render('ChillThirdPartyBundle:ThirdParty:index.html.twig', [ 'third_parties' => $thirdParties, - 'pagination' => $pagination - )); + 'pagination' => $pagination, + ]); } /** @@ -90,49 +96,64 @@ class ThirdPartyController extends Controller public function newAction(Request $request) { $this->denyAccessUnlessGranted(ThirdPartyVoter::CREATE); - + $centers = $this->authorizationHelper ->getReachableCenters( - $this->getUser(), + $this->getUser(), new Role(ThirdPartyVoter::CREATE) - ); - + ); + if (count($centers) === 0) { - throw new \LogicException("There should be at least one center reachable " - . "if role ".ThirdPartyVoter::CREATE." is granted"); + throw new LogicException('There should be at least one center reachable ' + . 'if role ' . ThirdPartyVoter::CREATE . ' is granted'); } - + $thirdParty = new ThirdParty(); $thirdParty->setCenters(new ArrayCollection($centers)); - + $form = $this->createForm(ThirdPartyType::class, $thirdParty, [ - 'usage' => 'create' + 'usage' => 'create', ]); $form->add('submit', SubmitType::class); - + $form->handleRequest($request); - + if ($form->isSubmitted() && $form->isValid()) { $em = $this->getDoctrine()->getManager(); $em->persist($thirdParty); $em->flush(); - - $this->addFlash('success', - $this->translator->trans("Third party created") - ); - + + $this->addFlash( + 'success', + $this->translator->trans('Third party created') + ); + return $this->redirectToRoute('chill_3party_3party_show', [ - 'thirdparty_id' => $thirdParty->getId() + 'thirdparty_id' => $thirdParty->getId(), ]); - - } elseif ($form->isSubmitted()) { + } + + if ($form->isSubmitted()) { $msg = $this->translator->trans('This form contains errors'); $this->addFlash('error', $msg); } - + return $this->render('@ChillThirdParty/ThirdParty/new.html.twig', [ 'form' => $form->createView(), - 'thirdParty' => $thirdParty + 'thirdParty' => $thirdParty, + ]); + } + + /** + * @Route("/{thirdparty_id}/show", name="chill_3party_3party_show") + * @ParamConverter("thirdParty", options={"id": "thirdparty_id"}) + */ + public function showAction(ThirdParty $thirdParty, Request $request) + { + $this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW, $thirdParty); + + return $this->render('@ChillThirdParty/ThirdParty/show.html.twig', [ + 'thirdParty' => $thirdParty, ]); } @@ -142,71 +163,60 @@ class ThirdPartyController extends Controller */ public function updateAction(ThirdParty $thirdParty, Request $request) { - $this->denyAccessUnlessGranted(ThirdPartyVoter::CREATE); - + $this->denyAccessUnlessGranted(ThirdPartyVoter::CREATE); + $centers = $this->authorizationHelper ->getReachableCenters( - $this->getUser(), + $this->getUser(), new Role(ThirdPartyVoter::CREATE) - ); - + ); + if (count($centers) === 0) { - throw new \LogicException("There should be at least one center reachable " - . "if role ".ThirdPartyVoter::CREATE." is granted"); + throw new LogicException('There should be at least one center reachable ' + . 'if role ' . ThirdPartyVoter::CREATE . ' is granted'); } - + // we want to keep centers the users has no access to. So we will add them // later if they are removed. (this is a ugly hack but it will works - $centersAssociatedNotForUsers = \array_diff( - $thirdParty->getCenters()->toArray(), - $centers); - + $centersAssociatedNotForUsers = array_diff( + $thirdParty->getCenters()->toArray(), + $centers + ); + $form = $this->createForm(ThirdPartyType::class, $thirdParty, [ - 'usage' => 'create' + 'usage' => 'create', ]); $form->add('submit', SubmitType::class); - + $form->handleRequest($request); - + if ($form->isSubmitted() && $form->isValid()) { // re-add centers the user has no accesses: foreach ($centersAssociatedNotForUsers as $c) { $thirdParty->addCenter($c); } - + $em = $this->getDoctrine()->getManager(); $em->flush(); - - $this->addFlash('success', - $this->translator->trans("Third party updated") - ); - + + $this->addFlash( + 'success', + $this->translator->trans('Third party updated') + ); + return $this->redirectToRoute('chill_3party_3party_show', [ - 'thirdparty_id' => $thirdParty->getId() + 'thirdparty_id' => $thirdParty->getId(), ]); - - } elseif ($form->isSubmitted()) { + } + + if ($form->isSubmitted()) { $msg = $this->translator->trans('This form contains errors'); $this->addFlash('error', $msg); } - + return $this->render('@ChillThirdParty/ThirdParty/update.html.twig', [ 'form' => $form->createView(), - 'thirdParty' => $thirdParty + 'thirdParty' => $thirdParty, ]); } - - /** - * @Route("/{thirdparty_id}/show", name="chill_3party_3party_show") - * @ParamConverter("thirdParty", options={"id": "thirdparty_id"}) - */ - public function showAction(ThirdParty $thirdParty, Request $request) - { - $this->denyAccessUnlessGranted(ThirdPartyVoter::SHOW, $thirdParty); - - return $this->render('@ChillThirdParty/ThirdParty/show.html.twig', [ - 'thirdParty' => $thirdParty - ]); - } - } diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php index 28e3c19df..79cea5b5c 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/ChillThirdPartyExtension.php @@ -1,30 +1,34 @@ processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../config')); $loader->load('services.yaml'); $loader->load('services/controller.yaml'); $loader->load('services/form.yaml'); @@ -40,26 +44,26 @@ class ChillThirdPartyExtension extends Extension implements PrependExtensionInte $this->preprendRoutes($container); $this->prependRoleHierarchy($container); } - + + protected function prependRoleHierarchy(ContainerBuilder $container) + { + $container->prependExtensionConfig('security', [ + 'role_hierarchy' => [ + ThirdPartyVoter::CREATE => [ThirdPartyVoter::SHOW], + ThirdPartyVoter::UPDATE => [ThirdPartyVoter::SHOW], + ], + ]); + } + protected function preprendRoutes(ContainerBuilder $container) { //declare routes for 3party bundle - $container->prependExtensionConfig('chill_main', array( - 'routing' => array( - 'resources' => array( - '@ChillThirdPartyBundle/config/routes.yaml' - ) - ) - )); - } - - protected function prependRoleHierarchy(ContainerBuilder $container) - { - $container->prependExtensionConfig('security', array( - 'role_hierarchy' => array( - ThirdPartyVoter::CREATE => [ThirdPartyVoter::SHOW], - ThirdPartyVoter::UPDATE => [ThirdPartyVoter::SHOW], - ) - )); + $container->prependExtensionConfig('chill_main', [ + 'routing' => [ + 'resources' => [ + '@ChillThirdPartyBundle/config/routes.yaml', + ], + ], + ]); } } diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php index e15510a5b..317e75ffb 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/CompilerPass/ThirdPartyTypeCompilerPass.php @@ -1,38 +1,49 @@ getDefinition(ThirdPartyTypeManager::class); $usedKeys = []; - + foreach ($container->findTaggedServiceIds(self::TAG) as $id => $tags) { $taggedService = $container->getDefinition($id); // check forr keys already in use : $key = $taggedService->getClass()::getKey(); - if (\in_array($key, $usedKeys)) { - throw new \LogicException(sprintf("Tag with key \"%s\" is already in used", - $key)); + + if (in_array($key, $usedKeys)) { + throw new LogicException(sprintf( + 'Tag with key "%s" is already in used', + $key + )); } $usedKeys[] = $key; // alter the service definition of manager - $definition->addMethodCall('addProvider', [ new Reference($id) ]); + $definition->addMethodCall('addProvider', [new Reference($id)]); } } } diff --git a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/Configuration.php index ad5aac291..7b34a329e 100644 --- a/src/Bundle/ChillThirdPartyBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillThirdPartyBundle/DependencyInjection/Configuration.php @@ -1,5 +1,12 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace Chill\ThirdPartyBundle\Entity; -use Doctrine\ORM\Mapping as ORM; -use Doctrine\Common\Collections\Collection; -use Doctrine\Common\Collections\ArrayCollection; -use Chill\MainBundle\Entity\Center; -use Symfony\Component\Validator\Constraints as Assert; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Entity\Center; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; +use Symfony\Component\Validator\Constraints as Assert; + +use function array_values; /** * ThirdParty is a party recorded in the database. - * - * A party may be attached to multiple centers. Being attach to a center allow - * all users with the right 'CHILL_3PARTY_3PARTY_SEE', 'CHILL_3PARTY_3 to see, select and edit parties for this + * + * A party may be attached to multiple centers. Being attach to a center allow + * all users with the right 'CHILL_3PARTY_3PARTY_SEE', 'CHILL_3PARTY_3 to see, select and edit parties for this * center. * * @ORM\Table(name="chill_3party.third_party") * @ORM\Entity(repositoryClass="Chill\ThirdPartyBundle\Repository\ThirdPartyRepository") - * */ class ThirdParty { + /** + * @var bool + * @ORM\Column(name="active", type="boolean", options={"defaut": true}) + */ + private $active = true; + + /** + * @var Address|null + * @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address", + * cascade={"persist", "remove"}) + */ + private $address; + + /** + * @var Collection instances of Center + * @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center") + * @ORM\JoinTable(name="chill_3party.party_center") + * @Assert\Count(min=1) + */ + private $centers; + + /** + * @var string|null + * + * @ORM\Column(name="comment", type="text", nullable=true) + */ + private $comment; + + /** + * @var string|null + * + * @ORM\Column(name="email", type="string", length=255, nullable=true) + * @Assert\Email(checkMX=false) + */ + private $email; + /** * @var int * @@ -63,27 +87,12 @@ class ThirdParty * @var string|null * * @ORM\Column(name="telephone", type="string", length=64, nullable=true) - * @Assert\Regex("/^([\+{1}])([0-9\s*]{4,20})$/", - * message="Invalid phone number: it should begin with the international prefix starting with ""+"", hold only digits and be smaller than 20 characters. Ex: +33123456789" + * @Assert\Regex("/^([\+{1}])([0-9\s*]{4,20})$/", + * message="Invalid phone number: it should begin with the international prefix starting with ""+"", hold only digits and be smaller than 20 characters. Ex: +33123456789" * ) */ private $telephone; - /** - * @var string|null - * - * @ORM\Column(name="email", type="string", length=255, nullable=true) - * @Assert\Email(checkMX=false) - */ - private $email; - - /** - * @var string|null - * - * @ORM\Column(name="comment", type="text", nullable=true) - */ - private $comment; - /** * @var array|null * @@ -91,28 +100,7 @@ class ThirdParty * @Assert\Count(min=1) */ private $type; - - /** - * @var boolean - * @ORM\Column(name="active", type="boolean", options={"defaut": true}) - */ - private $active = true; - - /** - * @var Collection instances of Center - * @ORM\ManyToMany(targetEntity="\Chill\MainBundle\Entity\Center") - * @ORM\JoinTable(name="chill_3party.party_center") - * @Assert\Count(min=1) - */ - private $centers; - - /** - * @var Address|null - * @ORM\ManyToOne(targetEntity="\Chill\MainBundle\Entity\Address", - * cascade={"persist", "remove"}) - */ - private $address; - + /** * ThirdParty constructor. */ @@ -122,95 +110,33 @@ class ThirdParty } /** - * Get id. - * - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * Set name. - * - * @param string $name - * @return ThirdParty - */ - public function setName($name) - { - $this->name = $name; - - return $this; - } - - /** - * Get name. - * * @return string */ - public function getName() + public function __toString() { - return $this->name; + return $this->getName(); } - /** - * Set telephone. - * - * @param string|null $telephone - * @return ThirdParty - */ - public function setTelephone($telephone = null) + public function addCenter(Center $center) { - $this->telephone = $telephone; - - return $this; + if (false === $this->centers->contains($center)) { + $this->centers->add($center); + } } - /** - * Get telephone. - * - * @return string|null - */ - public function getTelephone() + public function getActive(): bool { - return $this->telephone; + return $this->active; } - /** - * Set email. - * - * @param string|null $email - * @return ThirdParty - */ - public function setEmail($email = null) + public function getAddress(): ?Address { - $this->email = $email; - - return $this; + return $this->address; } - /** - * Get email. - * - * @return string|null - */ - public function getEmail() + public function getCenters(): Collection { - return $this->email; - } - - /** - * Set comment. - * - * @param string|null $comment - * @return ThirdParty - */ - public function setComment($comment = null) - { - $this->comment = $comment; - - return $this; + return $this->centers; } /** @@ -224,17 +150,43 @@ class ThirdParty } /** - * Set type. + * Get email. * - * @param array|null $type - * @return ThirdParty + * @return string|null */ - public function setType(array $type = null) + public function getEmail() { - // remove all keys from the input data - $this->type = \array_values($type); + return $this->email; + } - return $this; + /** + * Get id. + * + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * Get name. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get telephone. + * + * @return string|null + */ + public function getTelephone() + { + return $this->telephone; } /** @@ -246,55 +198,35 @@ class ThirdParty { return $this->type; } - - /** - * @return bool - */ - public function getActive(): bool - { - return $this->active; - } - - /** - * @return Collection - */ - public function getCenters(): Collection - { - return $this->centers; - } - - /** - * @param bool $active - * @return $this - */ - public function setActive(bool $active) - { - $this->active = $active; - return $this; - } - - /** - * @param Center $center - */ - public function addCenter(Center $center) - { - if (FALSE === $this->centers->contains($center)) { - $this->centers->add($center); - } - } - - /** - * @param Center $center - */ + public function removeCenter(Center $center) { if ($this->centers->contains($center)) { $this->centers->removeElement($center); } } - + + /** + * @return $this + */ + public function setActive(bool $active) + { + $this->active = $active; + + return $this; + } + + /** + * @return $this + */ + public function setAddress(Address $address) + { + $this->address = $address; + + return $this; + } + /** - * @param Collection $centers * @return $this */ public function setCenters(Collection $centers) @@ -302,40 +234,82 @@ class ThirdParty foreach ($centers as $center) { $this->addCenter($center); } - + foreach ($this->centers as $center) { - if (FALSE === $centers->contains($center)) { + if (false === $centers->contains($center)) { $this->removeCenter($center); } } - + return $this; } - + /** - * @return Address|null + * Set comment. + * + * @param string|null $comment + * + * @return ThirdParty */ - public function getAddress(): ?Address + public function setComment($comment = null) { - return $this->address; - } - - /** - * @param Address $address - * @return $this - */ - public function setAddress(Address $address) - { - $this->address = $address; - + $this->comment = $comment; + return $this; } - + /** - * @return string + * Set email. + * + * @param string|null $email + * + * @return ThirdParty */ - public function __toString() + public function setEmail($email = null) { - return $this->getName(); + $this->email = $email; + + return $this; + } + + /** + * Set name. + * + * @param string $name + * + * @return ThirdParty + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Set telephone. + * + * @param string|null $telephone + * + * @return ThirdParty + */ + public function setTelephone($telephone = null) + { + $this->telephone = $telephone; + + return $this; + } + + /** + * Set type. + * + * @return ThirdParty + */ + public function setType(?array $type = null) + { + // remove all keys from the input data + $this->type = array_values($type); + + return $this; } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php b/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php index a3c7e154b..fd0a513f2 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ChoiceLoader/ThirdPartyChoiceLoader.php @@ -1,45 +1,50 @@ center = $center; $this->partyRepository = $partyRepository; } - public function loadChoiceList($value = null): ChoiceListInterface { return new ArrayChoiceList($this->lazyLoadedParties, $value); @@ -48,39 +53,40 @@ class ThirdPartyChoiceLoader implements ChoiceLoaderInterface public function loadChoicesForValues($values, $value = null) { $choices = []; - - foreach($values as $value) { + + foreach ($values as $value) { if (empty($value)) { continue; } - + $party = $this->partyRepository->find($value); - - if (FALSE === \in_array($this->center, $party->getCenters()->toArray())) { - throw new \RuntimeException("the party's center is not authorized"); + + if (false === in_array($this->center, $party->getCenters()->toArray())) { + throw new RuntimeException("the party's center is not authorized"); } - + $choices[] = $party; } return $choices; } - + public function loadValuesForChoices(array $choices, $value = null) { $values = []; - + foreach ($choices as $choice) { - if (NULL === $choice) { + if (null === $choice) { $values[] = null; + continue; } - - $id = \call_user_func($value, $choice); + + $id = call_user_func($value, $choice); $values[] = $id; $this->lazyLoadedParties[$id] = $choice; } - + return $values; } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php index e6ecb4b26..f7e88eb97 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -1,45 +1,48 @@ tokenStorage = $tokenStorage; $this->typesManager = $typesManager; } - - /** - * {@inheritdoc} - */ + public function buildForm(FormBuilderInterface $builder, array $options) { $types = []; + foreach ($this->typesManager->getProviders() as $key => $provider) { - $types['chill_3party.key_label.'.$key] = $key; + $types['chill_3party.key_label.' . $key] = $key; } - + $builder ->add('name', TextType::class, [ - 'required' => true + 'required' => true, ]) ->add('telephone', TextType::class, [ 'label' => 'Phonenumber', - 'required' => false + 'required' => false, ]) ->add('email', EmailType::class, [ - 'required' => false + 'required' => false, ]) ->add('comment', TextareaType::class, [ - 'required' => false + 'required' => false, ]) ->add('type', ChoiceType::class, [ 'choices' => $types, 'expanded' => true, 'multiple' => true, - 'label' => 'thirdparty.Type' + 'label' => 'thirdparty.Type', ]) ->add('active', ChoiceType::class, [ 'choices' => [ 'Active, shown to users' => true, - 'Inactive, not shown to users' => false + 'Inactive, not shown to users' => false, ], 'expanded' => true, - 'multiple' => false + 'multiple' => false, ]) ->add('centers', EntityType::class, [ 'choices' => $this->getReachableCenters($options), 'class' => \Chill\MainBundle\Entity\Center::class, 'multiple' => true, - 'expanded' => true + 'expanded' => true, ]) ->add('address', AddressType::class, [ 'has_valid_from' => false, 'null_if_empty' => true, - 'required' => false - ]) - ; - } - - /** - * - * @param array $options - * @return \Chill\MainBundle\Entity\Center[] - */ - protected function getReachableCenters(array $options) - { - switch($options['usage']) { - case 'create': $role = new Role(ThirdPartyVoter::CREATE); - break; - case 'update': $role = new Role(ThirdPartyVoter::UPDATE); - break; - } - - return $this->authorizationHelper->getReachableCenters( - $this->tokenStorage->getToken()->getUser(), $role); - } - - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults(array( - 'data_class' => 'Chill\ThirdPartyBundle\Entity\ThirdParty' - )); - - $resolver->setRequired('usage') - ->setAllowedValues('usage', ['create', 'update']) - ; + 'required' => false, + ]); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => 'Chill\ThirdPartyBundle\Entity\ThirdParty', + ]); + + $resolver->setRequired('usage') + ->setAllowedValues('usage', ['create', 'update']); } - /** - * {@inheritdoc} - */ public function getBlockPrefix() { return 'chill_thirdpartybundle_thirdparty'; } + /** + * @return \Chill\MainBundle\Entity\Center[] + */ + protected function getReachableCenters(array $options) + { + switch ($options['usage']) { + case 'create': + $role = new Role(ThirdPartyVoter::CREATE); + break; + + case 'update': + $role = new Role(ThirdPartyVoter::UPDATE); + + break; + } + + return $this->authorizationHelper->getReachableCenters( + $this->tokenStorage->getToken()->getUser(), + $role + ); + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php index 98d3e585b..6db08eeda 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyType.php @@ -1,55 +1,56 @@ typesManager = $typesManager; } - - public function configureOptions(OptionsResolver $resolver) - { - $resolver - ->setRequired('center') - ->setAllowedTypes('center', [ \Chill\MainBundle\Entity\Center::class ]) - ->setDefined('types') - ->setRequired('types') - ->setAllowedValues('types', function($types) { - if (FALSE === \is_array($types)) { - return false; - } - // return false if one element is not contained in allowed types - return count(\array_diff($types, $this->typesManager->getTypes())) === 0; - }) - ; - - $resolver - ->setDefault('class', ThirdParty::class) - ->setDefault('choice_label', function(ThirdParty $tp) { - return $tp->getName(); - }) - ->setDefault('choice_loader', function(Options $options) { - return new ThirdPartyChoiceLoader($options['center'], - $this->em->getRepository(ThirdParty::class)); - }) - ; - } - - public function getParent(): string - { - return EntityType::class; - } - public function buildView(\Symfony\Component\Form\FormView $view, \Symfony\Component\Form\FormInterface $form, array $options) { - $view->vars['attr']['class'] = \array_merge(['select2 '], $view->vars['attr']['class'] ?? []); + $view->vars['attr']['class'] = array_merge(['select2 '], $view->vars['attr']['class'] ?? []); $view->vars['attr']['data-3party-picker'] = true; $view->vars['attr']['data-select-interactive-loading'] = true; $view->vars['attr']['data-search-url'] = $this->urlGenerator - ->generate('chill_main_search', [ - 'name' => ThirdPartySearch::NAME, - SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS => ['t' => $options['types']], - '_format' => 'json' ] - ); + ->generate( + 'chill_main_search', + [ + 'name' => ThirdPartySearch::NAME, + SearchInterface::REQUEST_QUERY_KEY_ADD_PARAMETERS => ['t' => $options['types']], + '_format' => 'json', ] + ); $view->vars['attr']['data-placeholder'] = $this->translator->trans($options['placeholder']); $view->vars['attr']['data-no-results-label'] = $this->translator->trans('select2.no_results'); $view->vars['attr']['data-error-load-label'] = $this->translator->trans('select2.error_loading'); $view->vars['attr']['data-searching-label'] = $this->translator->trans('select2.searching'); } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setRequired('center') + ->setAllowedTypes('center', [\Chill\MainBundle\Entity\Center::class]) + ->setDefined('types') + ->setRequired('types') + ->setAllowedValues('types', function ($types) { + if (false === is_array($types)) { + return false; + } + // return false if one element is not contained in allowed types + return count(array_diff($types, $this->typesManager->getTypes())) === 0; + }); + + $resolver + ->setDefault('class', ThirdParty::class) + ->setDefault('choice_label', function (ThirdParty $tp) { + return $tp->getName(); + }) + ->setDefault('choice_loader', function (Options $options) { + return new ThirdPartyChoiceLoader( + $options['center'], + $this->em->getRepository(ThirdParty::class) + ); + }); + } + + public function getParent(): string + { + return EntityType::class; + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php b/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php index 654c47e86..f04f1dc82 100644 --- a/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php +++ b/src/Bundle/ChillThirdPartyBundle/Menu/MenuBuilder.php @@ -1,49 +1,35 @@ , - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -namespace Chill\ThirdPartyBundle\Menu; - -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Translation\TranslatorInterface; -use Knp\Menu\MenuItem; -use Chill\MainBundle\Routing\LocalMenuBuilderInterface; -use Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter; /** - * Add an entry in section to go to third party index page + * Chill is a software for social workers * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Chill\ThirdPartyBundle\Menu; + +use Chill\MainBundle\Routing\LocalMenuBuilderInterface; +use Chill\ThirdPartyBundle\Security\Voter\ThirdPartyVoter; +use Knp\Menu\MenuItem; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Translation\TranslatorInterface; + +/** + * Add an entry in section to go to third party index page. */ class MenuBuilder implements LocalMenuBuilderInterface { /** - * * @var AuthorizationCheckerInterface */ protected $authorizationChecker; - + /** - * * @var TranslatorInterface */ protected $translator; - + public function __construct( AuthorizationCheckerInterface $authorizationChecker, TranslatorInterface $translator @@ -52,20 +38,19 @@ class MenuBuilder implements LocalMenuBuilderInterface $this->translator = $translator; } - public function buildMenu($menuId, MenuItem $menu, array $parameters) { if ($this->authorizationChecker->isGranted(ThirdPartyVoter::SHOW)) { $menu ->addChild( - $this->translator->trans('Third parties'), + $this->translator->trans('Third parties'), [ 'route' => 'chill_3party_3party_index', - ]) + ] + ) ->setExtras([ - 'order' => 112 - ]) - ; + 'order' => 112, + ]); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php index c961b3601..a0c8cc0dd 100644 --- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php +++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyRepository.php @@ -1,63 +1,72 @@ buildQuery($centers, $terms); $qb->select('COUNT(tp)'); - + return $qb->getQuery()->getSingleScalarResult(); } - + /** - * Search amongst parties associated to $centers, with $terms parameters - * + * Search amongst parties associated to $centers, with $terms parameters. + * * Different format for return: * - ['entity']: return the entity hydrated as objects - * - ['array', [ DQL ]: return objects hydrated as entity, with + * - ['array', [ DQL ]: return objects hydrated as entity, with * an array describing the fields as DQL. - * + * * supported terms: - * + * * - name or _default: containing the name (name LIKE %string%) * - is_active: is active = true / false * - types: an array of types - * - * @param array $centers + * * @param int $firstResult * @param int $maxResults * @param array $terms * @param string[] $returnFormat a format for returning - * @return array */ public function findByMemberOfCenters(array $centers, $firstResult = 0, $maxResults = 20, $terms = [], $returnFormat = ['entity']): array { $qb = $this->buildQuery($centers, $terms); - switch($returnFormat[0]) { + + switch ($returnFormat[0]) { case 'entity': $qb->select('tp'); $hydrate = Query::HYDRATE_OBJECT; + break; + case 'array': $hydrate = Query::HYDRATE_ARRAY; $first = true; + foreach ($returnFormat[1] as $dql) { if ($first) { $qb->select($dql); @@ -66,80 +75,81 @@ class ThirdPartyRepository extends \Doctrine\ORM\EntityRepository $qb->addSelect($dql); } } + break; + default: - throw new \DomainException("This return format is invalid"); - } + throw new DomainException('This return format is invalid'); + } $qb->setFirstResult($firstResult) ->setMaxResults($maxResults); - + return $qb->getQuery()->getResult(); } - - protected function createMemberOfCentersQuery($centers): QueryBuilder - { - $qb = $this->createQueryBuilder('tp'); - - $or = $qb->expr()->orX(); - - foreach ($centers as $center) { - $or->add($qb->expr()->isMemberOf(':center_'.$center->getId(), 'tp.centers')); - $qb->setParameter('center_'.$center->getId(), $center); - } - - $qb->where($or); - - return $qb; - } - + protected function buildQuery($centers, $terms): QueryBuilder { $qb = $this->createMemberOfCentersQuery($centers); $this->setNameCondition($qb, $terms); $this->setTypesCondition($qb, $terms); $this->setIsActiveCondition($qb, $terms); - + return $qb; } - + + protected function createMemberOfCentersQuery($centers): QueryBuilder + { + $qb = $this->createQueryBuilder('tp'); + + $or = $qb->expr()->orX(); + + foreach ($centers as $center) { + $or->add($qb->expr()->isMemberOf(':center_' . $center->getId(), 'tp.centers')); + $qb->setParameter('center_' . $center->getId(), $center); + } + + $qb->where($or); + + return $qb; + } + + protected function setIsActiveCondition(QueryBuilder $qb, array $terms) + { + if (array_key_exists('is_active', $terms)) { + $qb->andWhere( + $terms['is_active'] ? $qb->expr()->eq('tp.active', "'TRUE'") : + $qb->expr()->eq('tp.active', "'FALSE'") + ); + } + } + /** - * Add parameters to filter by containing $terms["name"] or - * $terms["_default"] - * - * @param QueryBuilder $qb - * @param array $terms + * Add parameters to filter by containing $terms["name"] or + * $terms["_default"]. */ protected function setNameCondition(QueryBuilder $qb, array $terms) { - if (\array_key_exists('name', $terms) || \array_key_exists('_default', $terms)) { + if (array_key_exists('name', $terms) || array_key_exists('_default', $terms)) { $term = $terms['name'] ?? $terms['_default']; + if (empty($term)) { return; } $qb->andWhere($qb->expr()->like('UNACCENT(LOWER(tp.name))', 'UNACCENT(LOWER(:name))')); - $qb->setParameter('name', '%'.$term.'%'); + $qb->setParameter('name', '%' . $term . '%'); } } - + protected function setTypesCondition(QueryBuilder $qb, array $terms) { - if (\array_key_exists('types', $terms)) { + if (array_key_exists('types', $terms)) { $orx = $qb->expr()->orX(); + foreach ($terms['types'] as $type) { - $orx->add('JSONB_EXISTS_IN_ARRAY(tp.type, :type_'.$type.') = \'TRUE\''); - $qb->setParameter('type_'.$type, $type); + $orx->add('JSONB_EXISTS_IN_ARRAY(tp.type, :type_' . $type . ') = \'TRUE\''); + $qb->setParameter('type_' . $type, $type); } $qb->andWhere($orx); } } - - protected function setIsActiveCondition(QueryBuilder $qb, array $terms) - { - if (\array_key_exists('is_active', $terms)) { - $qb->andWhere( - $terms['is_active'] ? $qb->expr()->eq('tp.active', "'TRUE'") : - $qb->expr()->eq('tp.active', "'FALSE'") - ); - } - } } diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php index 16984ea68..88e7d0639 100644 --- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php +++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php @@ -1,53 +1,54 @@ em = $em; @@ -56,7 +57,6 @@ class ThirdPartySearch implements SearchInterface $this->paginatorFactory = $paginatorFactory; } - public function getOrder(): int { return 59866; @@ -67,34 +67,39 @@ class ThirdPartySearch implements SearchInterface return false; } - public function renderResult(array $terms, $start = 0, $limit = 50, $options = array(), $format = 'html') + public function renderResult(array $terms, $start = 0, $limit = 50, $options = [], $format = 'html') { $centers = $this->authorizationHelper ->getReachableCenters( - $this->tokenStorage->getToken()->getUser(), + $this->tokenStorage->getToken()->getUser(), new Role(ThirdPartyVoter::SHOW) - ); + ); $total = $this->count($centers, $terms); $paginator = $this->paginatorFactory->create($total); // replace types in terms by types in query $terms['types'] = $options[SearchInterface::REQUEST_QUERY_PARAMETERS]['t']; $terms['is_active'] = true; - - if ($format === 'json') { + + if ('json' === $format) { return [ 'results' => $this->em->getRepository(ThirdParty::class) - ->findByMemberOfCenters($centers, $start, $limit, $terms, - ['array', ['tp.id', 'tp.name AS text']]), - 'more' => $paginator->hasNextPage() + ->findByMemberOfCenters( + $centers, + $start, + $limit, + $terms, + ['array', ['tp.id', 'tp.name AS text']] + ), + 'more' => $paginator->hasNextPage(), ]; } } public function supports($domain, $format): bool { - return self::NAME === $domain and $format === 'json'; + return self::NAME === $domain and 'json' === $format; } - + protected function count($centers, $terms): int { return $this->em->getRepository(ThirdParty::class) diff --git a/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php b/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php index a1ce94e25..1ab290732 100644 --- a/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php +++ b/src/Bundle/ChillThirdPartyBundle/Security/Voter/ThirdPartyVoter.php @@ -1,90 +1,57 @@ authorizationHelper = $authorizationHelper; } - - protected function supports($attribute, $subject) - { - if ($subject instanceof ThirdParty) { - return \in_array($attribute, $this->getRoles()); - } elseif ($subject === NULL) { - return $attribute === self::CREATE || $attribute === self::SHOW ; - } - - return false; - } - - /** - * - * @param string $attribute - * @param ThirdParty|null $subject - * @param TokenInterface $token - * @return type - */ - protected function voteOnAttribute($attribute, $subject, TokenInterface $token) - { - $user = $token->getUser(); - - if (!$user instanceof User) { - return false; - } - - $centers = $this->authorizationHelper - ->getReachableCenters($user, new Role($attribute)); - - if ($subject === NULL) { - return count($centers) > 0; - } elseif ($subject instanceof ThirdParty) { - return count(\array_intersect($centers, $subject->getCenters()->toArray())) > 0; - } - - return false; - } - - public function getRoles(): array + public function getRoles(): array { return [ - self::CREATE, self::UPDATE, self::SHOW + self::CREATE, self::UPDATE, self::SHOW, ]; } public function getRolesWithHierarchy(): array { return [ - 'Third Party' => $this->getRoles() + 'Third Party' => $this->getRoles(), ]; } @@ -92,4 +59,45 @@ class ThirdPartyVoter extends AbstractChillVoter implements ProvideRoleHierarchy { return $this->getRoles(); } + + protected function supports($attribute, $subject) + { + if ($subject instanceof ThirdParty) { + return in_array($attribute, $this->getRoles()); + } + + if (null === $subject) { + return self::CREATE === $attribute || self::SHOW === $attribute; + } + + return false; + } + + /** + * @param string $attribute + * @param ThirdParty|null $subject + * + * @return type + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $user = $token->getUser(); + + if (!$user instanceof User) { + return false; + } + + $centers = $this->authorizationHelper + ->getReachableCenters($user, new Role($attribute)); + + if (null === $subject) { + return count($centers) > 0; + } + + if ($subject instanceof ThirdParty) { + return count(array_intersect($centers, $subject->getCenters()->toArray())) > 0; + } + + return false; + } } diff --git a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php index be2f82cb5..5cbb57176 100644 --- a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php +++ b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php @@ -1,74 +1,53 @@ - * - * 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 . + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ + namespace Chill\ThirdPartyBundle\Templating\Entity; use Chill\MainBundle\Templating\Entity\AbstractChillEntityRender; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Symfony\Bridge\Twig\TwigEngine; -/** - * - * - */ +use function array_merge; + class ThirdPartyRender extends AbstractChillEntityRender { /** - * * @var TwigEngine */ protected $templating; - + public function __construct(TwigEngine $templating) { $this->templating = $templating; } - + /** - * * @param ThirdParty $entity - * @param array $options - * @return string */ public function renderBox($entity, array $options): string { - $params = \array_merge( - [ 'with_valid_from' => true ], + $params = array_merge( + ['with_valid_from' => true], $options - ); - + ); + return - $this->getDefaultOpeningBox('_3party'). - $this->templating->render('@ChillThirdParty/ThirdParty/_render.html.twig', [ - 'contact' => $entity, - 'options' => $params - ]). + $this->getDefaultOpeningBox('_3party') . + $this->templating->render('@ChillThirdParty/ThirdParty/_render.html.twig', [ + 'contact' => $entity, + 'options' => $params, + ]) . $this->getDefaultClosingBox(); - } /** - * * @param ThirdParty $entity - * @param array $options - * @return string */ public function renderString($entity, array $options): string { diff --git a/src/Bundle/ChillThirdPartyBundle/Tests/Controller/ThirdPartyControllerTest.php b/src/Bundle/ChillThirdPartyBundle/Tests/Controller/ThirdPartyControllerTest.php index 9c3e187fc..58b6e1f4c 100644 --- a/src/Bundle/ChillThirdPartyBundle/Tests/Controller/ThirdPartyControllerTest.php +++ b/src/Bundle/ChillThirdPartyBundle/Tests/Controller/ThirdPartyControllerTest.php @@ -1,9 +1,20 @@ request('GET', '/update'); } - } diff --git a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php index aef7b1d35..af0f7de06 100644 --- a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php +++ b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeManager.php @@ -1,55 +1,60 @@ providers[$provider->getKey()] = $provider; - + return $this; } - + /** - * Get all providers - * - * @return array + * Get all providers. */ public function getProviders(): array { return $this->providers; } - + /** - * Get a list of types - * + * Get a list of types. + * * @return string[] */ public function getTypes(): array { - return \array_keys($this->providers); + return array_keys($this->providers); } } diff --git a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeProviderInterface.php b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeProviderInterface.php index d544255e9..8310480c5 100644 --- a/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeProviderInterface.php +++ b/src/Bundle/ChillThirdPartyBundle/ThirdPartyType/ThirdPartyTypeProviderInterface.php @@ -1,17 +1,21 @@ abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP SEQUENCE chill_third_party_id_seq CASCADE'); + $this->addSql('DROP TABLE chill_third_party'); + } + public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs @@ -20,16 +38,5 @@ final class Version20190307111314 extends AbstractMigration $this->addSql('CREATE SEQUENCE chill_third_party_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE chill_third_party (id INT NOT NULL, name VARCHAR(255) NOT NULL, telephone VARCHAR(64) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, comment TEXT DEFAULT NULL, type JSON DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('COMMENT ON COLUMN chill_third_party.type IS \'(DC2Type:json_array)\''); - - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP SEQUENCE chill_third_party_id_seq CASCADE'); - $this->addSql('DROP TABLE chill_third_party'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190307131650.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190307131650.php index 0d20c53b2..650e7e824 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190307131650.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190307131650.php @@ -1,4 +1,13 @@ -addSql("CREATE SCHEMA chill_3party"); - $this->addSql("ALTER TABLE chill_third_party SET SCHEMA chill_3party"); - $this->addSql("ALTER TABLE chill_3party.chill_third_party RENAME TO third_party"); - $this->addSql("ALTER SEQUENCE chill_third_party_id_seq SET SCHEMA chill_3party"); - $this->addSql("ALTER SEQUENCE chill_3party.chill_third_party_id_seq RENAME TO third_party_id_seq"); - } - public function down(Schema $schema): void { // this down() migration is auto-generated, please modify it to your needs - $this->throwIrreversibleMigrationException("The down version of this migration is " - . "not written"); + $this->throwIrreversibleMigrationException('The down version of this migration is ' + . 'not written'); + } + + public function up(Schema $schema): void + { + // this up() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SCHEMA chill_3party'); + $this->addSql('ALTER TABLE chill_third_party SET SCHEMA chill_3party'); + $this->addSql('ALTER TABLE chill_3party.chill_third_party RENAME TO third_party'); + $this->addSql('ALTER SEQUENCE chill_third_party_id_seq SET SCHEMA chill_3party'); + $this->addSql('ALTER SEQUENCE chill_3party.chill_third_party_id_seq RENAME TO third_party_id_seq'); } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190418090842.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190418090842.php index bb4900355..754263653 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190418090842.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190418090842.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('DROP TABLE chill_3party.party_center'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP active'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -21,12 +38,4 @@ final class Version20190418090842 extends AbstractMigration $this->addSql('ALTER TABLE chill_3party.party_center ADD CONSTRAINT FK_C65D43975932F377 FOREIGN KEY (center_id) REFERENCES centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('ALTER TABLE chill_3party.third_party ADD active BOOLEAN NOT NULL'); } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('DROP TABLE chill_3party.party_center'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP active'); - } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190429171109.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190429171109.php index 99e9806d7..ec62b7cd2 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190429171109.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190429171109.php @@ -1,4 +1,13 @@ -addSql("ALTER TABLE chill_3party.third_party RENAME COLUMN type " - . "TO types"); - $this->addSql("ALTER TABLE chill_3party.third_party ALTER COLUMN types " - . "SET DATA TYPE jsonb"); - - } - public function down(Schema $schema): void { - $this->throwIrreversibleMigrationException("not implemented"); + $this->throwIrreversibleMigrationException('not implemented'); + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_3party.third_party RENAME COLUMN type ' + . 'TO types'); + $this->addSql('ALTER TABLE chill_3party.third_party ALTER COLUMN types ' + . 'SET DATA TYPE jsonb'); } } diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190502144206.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190502144206.php index b19c1b833..b17fe5a49 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20190502144206.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20190502144206.php @@ -1,4 +1,13 @@ -abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BF5B7AF75'); + $this->addSql('ALTER TABLE chill_3party.third_party DROP address_id'); + } + public function up(Schema $schema): void { $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); @@ -18,14 +35,5 @@ final class Version20190502144206 extends AbstractMigration $this->addSql('COMMENT ON COLUMN chill_3party.third_party.types IS NULL'); $this->addSql('ALTER TABLE chill_3party.third_party ADD CONSTRAINT FK_D952467BF5B7AF75 FOREIGN KEY (address_id) REFERENCES chill_main_address (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_D952467BF5B7AF75 ON chill_3party.third_party (address_id)'); - - } - - public function down(Schema $schema): void - { - $this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'postgresql', 'Migration can only be executed safely on \'postgresql\'.'); - - $this->addSql('ALTER TABLE chill_3party.third_party DROP CONSTRAINT FK_D952467BF5B7AF75'); - $this->addSql('ALTER TABLE chill_3party.third_party DROP address_id'); } }